You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React添加商品后购物车表格不更新问题求助

问题:购物车组件添加商品后不重新渲染

我正在开发一个名为MakeASale的模拟结账组件,主组件维护cartItems状态,将其传递给CartTable2组件展示购物车商品的增删操作。把addToCart函数作为props传入InventoryModal组件,点击模态框的“Add to Cart”按钮能更新MakeASale的cartItems状态,但CartTable2组件不会随之重新渲染。只有修改searchFilter状态(比如在搜索框输入内容)时,表格才会刷新显示新增商品。我试过在CartTable2中添加监听props.data的useEffect,以及为tbody设置key,都没解决问题。


相关组件代码

MakeASale组件

const MakeASale = (props) => {
    
    const [searchFilter, setSearchFilter] = useState("");
    const [cartItems, setCartItems] = useState([]);

    const updateSearchFilter = (e) => {
        setSearchFilter(e.target.value);
        console.log(searchFilter);
    };

    const openInventoryModal = () => {
        var modal = document.getElementById("myModal");
        modal.style.display = "block";
    };

    const addToCart = (row) => {
        
        if(cartItems.findIndex((current) => current.PID === row.values.PID) >= 0){
            console.log("Cart Item Already Exists");
        }
        else {
            const newCartItem = { ...row.values };
        
            let updatedCartItems = cartItems;
            updatedCartItems.push(newCartItem);
            setCartItems(updatedCartItems);

            console.log(cartItems);
        }
        
    };

    const deleteFromCart = (PID) => {
        
        let updatedCartItems = [...cartItems];

        const deletedIndex = cartItems.findIndex((current) => current.PID === PID);
        updatedCartItems.splice(deletedIndex, 1);
        setCartItems(updatedCartItems);
    };

    return (
        <div className="makeASaleContainer">
            <h1>Make A Sale</h1>

            <section>
                <h2>Live Search:</h2>
                <input type="search" onChange={updateSearchFilter}></input>

                <CompleteInventoryModal uid={props.uid} addToCart={addToCart} />
            </section>

            <div className="makeASale-mainUI">
                <section>
                    <h2>Shopping Cart:</h2>
                    <CartTable2 data={cartItems} deletePID={deleteFromCart} />
                </section>

                <section className="makeASale-GUI-Container">
                    <h2>Controls:</h2>
                    <button onClick={openInventoryModal}>View Full Inventory</button>
                </section>

            </div> 
        </div>
    )
}

export default MakeASale;

CompleteInventoryModal组件

const CompleteInventoryModal = (props) => {
    
    const [products, setProducts] = useState([]);

    const fetchProducts = useCallback(() => {
        Axios.post('http://localhost:3001/request_full_inventory', { 
            uid: props.uid  
        })
        .then((response) => {
            if(response.status === 299){
                console.log(response);
                setProducts([]);
            }
            else{
                console.log(response);
                setProducts(response.data.data);
            }
        })
        .catch(error =>{
            console.log(error);
        })
    }, [props.uid]);

    useEffect(() => fetchProducts, [fetchProducts]);


    const closeInventoryModal = () => {
        var modal = document.getElementById("myModal");
        modal.style.display = "none";
    }

    return (
        <div id="myModal" className="modal">
        
          <div className="modal-content">
            <span className="close" onClick={closeInventoryModal}>&times;</span>
            <p>Complete Inventory Modal..</p>
            <CompleteInventoryTable data={products} addToCart={props.addToCart} />
          </div>
        
        </div>
    );
};

export default CompleteInventoryModal;

CartTable2组件

const CartTable2 = (props) => {
    
    const [cartData, setCartData] = useState(props.data);

    useEffect(() => { setCartData(props.data) }, [props.data]);

    return (
        <table>
            <thead>
                <tr>
                    <th>PID</th>
                    <th>Product Name</th>
                    <th>SKU</th>
                    <th>Barcode</th>
                </tr>
            </thead>
            <tbody key={cartData}>
                {
                    cartData.map((row) => {
                        return (
                            <tr key={row.PID}>
                                <td>{row.PID}</td>
                                <td>{row.pName}</td>
                                <td>{row.sku}</td>
                                <td>{row.barcode}</td>
                            </tr>
                        );
                    })
                }
            </tbody>
        </table>
    );
};

export default CartTable2;

问题根源及修复方案

1. 直接修改原数组导致React状态未更新

在addToCart函数中,你直接引用原cartItems数组并修改:

let updatedCartItems = cartItems;
updatedCartItems.push(newCartItem);
setCartItems(updatedCartItems);

React依赖状态的引用变化触发重渲染,这里updatedCartItems和原cartItems是同一个数组引用,React会判定状态未发生改变,因此不会触发组件重渲染。

修复方式: 创建新数组后再更新状态

// 解构原数组生成新数组,保证引用变化
let updatedCartItems = [...cartItems];
updatedCartItems.push(newCartItem);
setCartItems(updatedCartItems);

// 或更简洁的回调写法,确保拿到最新状态
setCartItems(prevCart => [...prevCart, newCartItem]);

2. 移除CartTable2的本地状态冗余

CartTable2中维护的本地状态cartData完全多余,直接使用父组件传递的props.data即可,避免父子状态不同步的问题。

简化后的CartTable2:

const CartTable2 = (props) => {
    return (
        <table>
            <thead>
                <tr>
                    <th>PID</th>
                    <th>Product Name</th>
                    <th>SKU</th>
                    <th>Barcode</th>
                </tr>
            </thead>
            <tbody>
                {
                    props.data.map((row) => {
                        return (
                            <tr key={row.PID}>
                                <td>{row.PID}</td>
                                <td>{row.pName}</td>
                                <td>{row.sku}</td>
                                <td>{row.barcode}</td>
                            </tr>
                        );
                    })
                }
            </tbody>
        </table>
    );
};

export default CartTable2;

3. 优化状态更新后的日志输出

setCartItems是异步操作,直接在更新后console.log(cartItems)会打印旧状态,可改为以下两种方式:

// 方式1:用回调获取最新状态并打印
setCartItems(prevCart => {
    const newCart = [...prevCart, newCartItem];
    console.log(newCart);
    return newCart;
});

// 方式2:用useEffect监听状态变化打印
useEffect(() => {
    console.log(cartItems);
}, [cartItems]);

内容的提问来源于stack exchange,提问作者lilhitchcock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 16:22:16