React自定义CartProvider调用更新函数后其他状态恢复默认值问题排查
问题根因
- 核心原因是闭包陈旧值 + 错误的state结构设计:你将
updateCoupon、updateDeliveryPersion两个更新方法也存入了state中。首次渲染生成的更新方法,闭包捕获的永远是初始state值(deliveryPersion:'own'、coupon:{})。 - 你第一次调用
updateDeliveryPersion更新状态时,合并的旧state里保存的是首次渲染生成的旧更新方法。后续你调用updateCoupon时,用的就是这个旧方法,它会基于初始state做合并,自然就把deliveryPersion覆盖回了默认值own。
修复方案
有两种常用修复方式:
方式1:拆分state,不把方法存入state(更推荐)
把数据状态和更新方法拆分,Context的value每次渲染都生成最新值,避免闭包问题:
import {createContext, useContext, useState} from 'react' const CartContext = createContext({ deliveryPersion:'own', coupon:{}, updateCoupon: (obj) => {}, updateDeliveryPersion: (type) => {}, }) export function CartProvider(props) { // 仅把数据存入state const [deliveryPersion, setDeliveryPersion] = useState('own') const [coupon, setCoupon] = useState({}) // 更新方法单独定义,不存入state const updateCoupon = (_coupon) => { setCoupon(_coupon) } const updateDeliveryPersion = (type) => { setDeliveryPersion(type) } // 组装最新的Context值 const contextValue = { deliveryPersion, coupon, updateCoupon, updateDeliveryPersion } return ( <CartContext.Provider value={contextValue}> {props.children} </CartContext.Provider> ) } export function useCartContext() { return useContext(CartContext); }
方式2:使用setState函数式更新
如果要保留单个state的结构,就用setState的函数式写法,直接读取最新的prev状态,不依赖闭包中的旧state:
const updateCoupon = (_coupon) => { // 用函数式更新获取最新的prev状态 setState(prev => ({...prev, coupon: _coupon})) } const updateDeliveryPersion = (type) => { setState(prev => ({...prev, deliveryPersion: type})) }
内容的提问来源于stack exchange,提问作者S.M_Emamian
相关产品推荐
相关产品推荐

