Ray
Ray

Reputation: 396

React Hook useState Not Updating UI

I am new to React Hooks and I'm trying to update the quantity in a shopping cart using the following code;

import React, { useState, useEffect } from "react";
import cookie from "react-cookies";
import CheckoutItems from "./CheckoutItems";
import restHelper from "../../shared/RestHelper";

const Checkout = () => {
    const [cart, setCart] = useState(null);

    useEffect(() => {
        const cartId = cookie.load("RbCartId");

        if (cartId){
            (async () => {
                const cart = await restHelper.getUserCart(cartId);
                setCart(cart);
            })();
            }
    }, []);

    const handleQtyUpdate = (evt, id) => {
        let _cart = cart;
        let items = _cart.cartItems.filter(x => x.id === id);
        let cartItem = { ...items[0] };
        cartItem.quantity = Number(evt.target.value);
        const index = _cart.cartItems.findIndex(x => x.id === cartItem.id);
        _cart.cartItems[index] = cartItem;
        setCart(_cart);
    };

    return (
        <section>
            <div className="container" style={{ marginTop: "80px" }}>
                <h3 className="rb-highlight">Shopping Cart</h3>
                <table className="table" style={{marginTop: "20px"}}>
                    <thead>
                        <tr>
                            <th>Items</th>
                            <th style={{ textAlign: "right" }}>Price</th>
                            <th style={{ textAlign: "right" }}>Quantity</th>
                            <th style={{ textAlign: "right" }}>Total</th>
                        </tr>
                    </thead>
                    <tbody>
                        <CheckoutItems cart={cart} onQtyUpdate={handleQtyUpdate} />
                    </tbody>
                </table>
            </div>
        </section>
    );
}
export default Checkout;

The CheckoutItems component is

import React from "react";

function CheckoutItems({cart, onQtyUpdate}){
    if (!cart || cart.cartItems === 0){
        return <tr><td colSpan="4"><span className="rb-highlight">There are no items in your cart</span></td></tr>;
    }
    else{
        const cartItems = cart.cartItems.map((item, index) => {
            return <tr key={index}>
                <td>{item.description}</td>
                <td style={{textAlign: "right"}}>&euro;{item.cost}</td>
                <td style={{textAlign: "right"}}><input type="text" id={item.id} name="quantity" value={item.quantity} onChange={(evt) => onQtyUpdate(evt, item.id)} /></td>
                <td style={{textAlign: "right"}}>&euro;{item.cost * item.quantity}</td>
            </tr>
        })
        return cartItems;
    }
}

export default CheckoutItems;

The cart items are successfully updated in handleQtyUpdate however the value isn't updated in the UI. From what I have read I should be using useEffect to update the cart but I'm not sure how to go about using it from handleQtyUpdate.

Upvotes: 6

Views: 7687

Answers (2)

F&#225;bio BC Souza
F&#225;bio BC Souza

Reputation: 1220

You should have a copy of the object using spread operator

setCart({..._cart})

Upvotes: 0

James
James

Reputation: 82096

The issue is state comparisons are shallow, meaning, in the case of an object only the reference will be compared.

In your example, you update the cartItems property but not the object instance, so as far as React is concerned the state hasn't changed because it won't check individual properties.

Try creating a completely new cart each time and you should see the UI update e.g.

 setCart({ ..._cart })

Upvotes: 23

Related Questions