React调用函数时旧状态残留:useCallback依赖users仍获旧值
问题:useCallback依赖users后,批量更新用户状态仅最后一个生效
问题现象
点击更新按钮后,期望为所有用户添加gender: 'male'字段,但实际仅最后一个用户完成更新。
期望输出
{"id":1,"name":"John","age":10,"gender":"male"} {"id":2,"name":"Stacy","age":15,"gender":"male"} {"id":3,"name":"Kevin","age":30,"gender":"male"} {"id":4,"name":"Jessi","age":13,"gender":"male"}
实际输出
{"id":1,"name":"John","age":10} {"id":2,"name":"Stacy","age":15} {"id":3,"name":"Kevin","age":30} {"id":4,"name":"Jessi","age":13,"gender":"male"}
问题原因
尽管给useCallback添加了users依赖,但startUpdate的循环中,所有updateUser调用都处于同一个事件循环周期内。React的状态更新是异步批量处理的,循环执行期间users状态不会立刻更新——所有updateUser调用引用的都是同一个初始的users快照。每次调用setUsers时,都是基于原始数组修改单个用户,后面的修改会覆盖前面的结果,最终只有最后一次修改被保留。
解决方案
方案1:使用函数式状态更新(推荐)
修改updateUser,利用React的函数式更新特性,每次更新都基于最新的前一次状态,而非直接引用当前users变量,同时useCallback无需再依赖users:
const updateUser = useCallback( (newUser) => { setUsers(prevUsers => prevUsers.map((user) => user.id === newUser.id ? newUser : user )); }, [] // 无需依赖users );
函数式更新会接收当前最新状态作为参数,确保每次更新都基于上一次的结果,循环中的每一次修改都会被正确累积。
方案2:一次性批量更新所有用户
既然目标是给所有用户添加字段,无需循环调用updateUser,直接生成完整的新数组后调用一次setUsers即可,这种方式更高效:
const startUpdate = () => { const updatedUsers = users.map(user => ({ ...user, gender: 'male' })); setUsers(updatedUsers); };
只需一次状态更新就能完成所有用户的修改,避免多次调用setUsers带来的问题。
内容的提问来源于stack exchange,提问作者Madhav mishra
相关产品推荐
相关产品推荐

