React如何正确将useContext值作为useEffect依赖项触发更新?
问题核心原因
你遇到的所有问题根源是更新数组state时直接修改了原数组(原地修改),React的state更新依赖引用变化触发重渲染,原地修改数组不会改变数组的引用,因此上下文传递的orderItems永远是同一个引用,自然无法触发依赖的更新检测。
修复步骤
1. 修正Context中的state更新逻辑
原代码中addOItemHandler用unshift、removeOItemHandler用splice都是原地修改操作,返回的还是原数组引用,需要改为返回全新数组:
// 修改添加条目的逻辑 function addOItemHandler(newOItem: OrderItem) { setOrderList((prevOrderList: OrderItem[]) => { // 展开原数组生成新数组,新元素放在头部,完全不修改原数组 return [newOItem, ...prevOrderList]; }); } // 修改删除条目的逻辑 function removeOItemHandler(oItemId: string) { setOrderList((prevOrderList: OrderItem[]) => { // filter直接返回符合条件的新数组,不需要手动操作原数组 return prevOrderList.filter(item => item.itemId !== oItemId); }); }
如果后续有修改单个条目属性的需求,更新时也要同时生成新数组和新的条目对象:
// 示例:修改条目的数量 function updateOrderItemAmount(itemId: string, newAmount: number) { setOrderList(prev => prev.map(item => { if (item.itemId === itemId) { // 展开原条目生成新对象,修改对应属性 return {...item, amount: newAmount}; } return item; })) }
2. 修正useEffect依赖项
修改完state更新逻辑后,只要orderItems发生任何变化(长度变化、单个条目属性变化),数组的引用都会更新,直接把NewOrderContext.orderItems加入依赖即可:
useEffect(() => { if (NewOrderContext.orderItems.length > 0) { const oItems: JSX.Element[] = []; NewOrderContext.orderItems.forEach((item) => { const fullItem = { itemId:item.itemId, name: item.name, amount: item.amount, more: item.more, }; oItems.push( <OItem item={fullItem} editItem={() => editItem(item.itemId)} key={item.itemId} /> ); }); setContent(<div>{oItems}</div>); } else { exit(); } // 直接用orderItems作为依赖即可 }, [NewOrderContext.orderItems, props.isOpen]);
其他说明
之前用Object.values(context)作为依赖能生效是因为你每次渲染都会新建context对象,Object.values每次返回的都是新数组,浅比较会判定为变化,但这种写法依赖不稳定的对象结构,不符合React依赖规范,会触发警告,完全不需要使用。如果要进一步优化Context性能,可以把所有handler用useCallback包裹,避免每次Provider渲染都生成新的context对象,减少不必要的消费组件重渲染。
内容的提问来源于stack exchange,提问作者Matus86309
相关产品推荐
相关产品推荐

