Home > Mobile >  React setState is not updating my react app
React setState is not updating my react app

Time:09-29

I am working on a simple react app. My task is to update the product price as the quantity updates. I have an array of products in my App.js file. And also two functions for increment and decrement of the quantity of the product.

import "./App.css";
import Navbar from "./components/navbar";
import ProductList from "./components/ProductList";
import Footer from "./components/Footer";
import React, { useState } from "react";

function App() {
  let productList = [
    {
      price: 99999,
      name: "Iphone 10S Max",
      quantity: 0,
    },
    {
      price: 999,
      name: "Realme 9 Pro",
      quantity: 0,
    },
  ];

  let [products, setState] = useState(productList);
  // console.log(useState(productList));

  const increamentQty = (inx) => {
    let newProductList = [...products];
    newProductList[inx].quantity  ;
    console.log(newProductList);
    setState(newProductList);
  };
  const decrementQty = (inx) => {
    let newProductList = [...products];
    newProductList[inx].quantity > 0
      ? newProductList[inx].quantity--
      : (newProductList[inx].quantity = 0);
    setState(newProductList);
  };

  return (
    <React.StrictMode>
      <Navbar />
      <div className="mt-5">
        <ProductList
          productList={productList}
          increamentQty={increamentQty}
          decrementQty={decrementQty}
        />
      </div>
      <Footer />
    </React.StrictMode>
  );
}

export default App;

I pass the function and the productList array to my ProductList component. This is the ProductList.js file.

import React from "react";
import Product from "./Product";

export default function ProductList(props) {
  return props.productList.map((product, i) => {
    return (
      <Product
        product={product}
        key={i}
        increamentQty={props.increamentQty}
        decrementQty={props.decrementQty}
        index={i}
      ></Product>
    );
  });
}

and then I pass the function and product index to Product component which will render out my products. This is the Product.js file

import React from "react";

export default function Product(props) {
  return (
    <div className="container">
      <div className="row">
        <div className="col-lg-4 col-sm-12 col-md-6">
          <h2>
            {props.product.name} &nbsp;
            <span className="badge bg-success">₹ {props.product.price}</span>
          </h2>
        </div>
        <div className="col-lg-4 col-md-6 col-sm-12">
          <div className="btn-group" role="group" aria-label="Basic example">
            <button
              type="button"
              className="btn btn-success"
              onClick={() => {
                props.increamentQty(props.index);
              }}
            >
               
            </button>

            <button type="button" className="btn btn-warning">
              {props.product.quantity}
            </button>

            <button
              type="submit"
              className="btn btn-danger"
              onClick={() => {
                props.decrementQty(props.index);
              }}
            >
              -
            </button>
          </div>
        </div>
        <div className="col-lg-4 col-sm-12 col-md-6">
          <p>{props.product.quantity * props.product.price}</p>
        </div>
      </div>
    </div>
  );
}

As you can see, I am using onClick event listener for my increase and decrease buttons. When I click the button, the quantity is updated, but that's not reflected in my DOM. How can I fix this?

CodePudding user response:

In addition to the other suggestions which should fix your issues (ie: using productList={products}), you're also currently modifying your state directly, which down the line can lead to other UI problems.

When you do:

let newProductList = [...products];

you're creating a shallow copy of the products array, but the objects within that array are still the original references to your state and are not copies. As a result, you need to create a new object within your new array when you want to update it to avoid rerender issues. One possible way is to use:

const newProductList = [...products];
const toUpdate = newProductList[inx];
newProductList[inx] = {...toUpdate, quantity: toUpdate.quantity 1};
setState(newProductList);

The same applies to your decrement logic. Here I've provided a slightly different example where I'm using the state setter function, but you can also use the above approach. I've created a copy of the state in the arguments and then used Math.max() instead of the ternary:

setState(([...products]) => {
  const toUpdate = newProductList[inx];
  products[inx] = {...toUpdate, quantity: Math.max(0, toUpdate.quantity-1)
  return products;
});

Always treat your state as read-only/immutable to avoid unexpected bugs with your UI. Other ways of achieving the above is to use .map() to create a new array and then replace your object when your map reaches the object that matches your inx value.

CodePudding user response:

In you App.js, change

productList={productList} 

to

productList={product}

CodePudding user response:

Just noticed the actual problem. You are passing down the default value for the state and not the state's value.

  • Related