Skip to content
Advertisement

Changing object in an array does not trigger change in html React

The object I want to edit gets edited in JSON format, but only previous data gets displayed in the browser. I use these hooks to get a list of products from local storage

const Cart = () => {
    const [products, setProducts] = useState([]);
    const [loading, setLoading] = useState(true);

    useEffect(()=>{
        setProducts(loadCart());
        setLoading(false)
    },[])

Then I map all of the objects

   const mapProducts = (products) => {
        return (
            <>
                {products.map((product) => {
                    return (
                        <>
                            <div className="cart-detail">
                                <h4>{product.name} - {product.price}$ 
                                / total: {product.price * product.amount}$</h4>

                                <h4>{product.amount}</h4>
                                <button onClick={() => incrementAmount(product)}>+</button>
                            </div>
                            
                        </>
                    )
                })}
            </>
        )
    }

    return (
        <Base title="Cart">
            {loading && <h1>Loading...</h1>}
            {!loading && mapProducts(products)}
        </Base>
    )

incrementAmount() function looks like that:

    const incrementAmount = (product) => {
        let tempList = products
        for (let i = 0; i < tempList.length; i++) {
            if (tempList[i].id === product.id) {
                tempList[i].amount++;
            }
        }
        setProducts(tempList)
    }

From what I see in the console, the array looks fine and the object I wanted to edit got edited. FE: I had an object {name:”hoodie”, amount:3} after clicking “+” button it changes properly to {name:”hoodie”, amount:4} (in both products and tempList) but in console only, in the document it still displays product.amount as 3 and I have no idea why

Advertisement

Answer

Instead of pass an object to setState you can pass a function and when you have an object into the state that you want to keep old values you must use a function.

Because state may be updated asynchronously, you should not rely on their values for calculating the next state.

You must change the incrementAmount() function like this:

const incrementAmount = (product) => {
    setProducts(prevState => {
        const newState = [...prevState];
        for (let i = 0; i < newState.length; i++) {
          if (newState[i].id === product.id) {
            newState[i].amount++;
          }
        }
        return newState;
     });
}
Advertisement