React组件数组回调函数无法获取最新state问题咨询
React状态打印旧值问题成因
核心原因是闭包捕获加上错误的state存储方式,具体如下:
- 函数组件每触发一次重渲染,都会完整执行一次组件代码,生成新的
deleteThisPersonHandler函数,每个函数都会捕获当前渲染周期对应的personArrOfComp状态值,不同渲染周期生成的handler互相独立,捕获的状态值也都是各自渲染时的快照。 - 你的代码里直接把
<Person />组件实例存在了useState中:初始化state时绑定的是第一次渲染生成的旧handler,后续每次调用addNewPersonHandler新增Person组件时,绑定的都是新增那个时刻的handler。后续组件重渲染生成新的handler后,已经存在state里的所有旧Person实例不会更新props,它们的deleteThisPerson还是指向创建时绑定的旧handler,所以调用时打印的永远是handler创建时的旧状态,拿不到最新值。 - 额外说明:将组件实例直接存入state本身就是React不推荐的写法,state应该只存纯数据(如人员的id、姓名、年龄字段),渲染时遍历数据生成组件即可,就能天然避免这个问题。
修复示例代码
import React, { useState } from "react"; const Person = ({ id, name, age, deleteThisPerson }) => { return ( <div className="person"> <p>{name}</p> <p>{age}</p> <button onClick={() => deleteThisPerson(id)}>Delete This Person</button> </div> ); }; const ArrayOfComponents = () => { // state只存纯数据,不存组件实例 const [personList, setPersonList] = useState([ { id: "pc1", name: "pc1", age: 12 } ]); const deleteThisPersonHandler = (id) => { console.log("[ArrayOfComponents] id : ", id); console.log("[ArrayOfComponents] 最新的personList : ", personList); // 执行删除逻辑 setPersonList(prev => prev.filter(item => item.id !== id)) }; const addNewPersonHandler = () => { let r = new Date().getTime().toString(); setPersonList((prevState) => { return prevState.concat({ id: r, name: "PCC" + r, age: Math.floor(Math.random() * 100) }) }); }; // 渲染时遍历数据生成组件 return ( <div> <button onClick={addNewPersonHandler}>Add New Person</button> {personList.map(person => ( <Person key={person.id} id={person.id} name={person.name} age={person.age} deleteThisPerson={deleteThisPersonHandler} /> ))} </div> ); }; export default ArrayOfComponents;
内容的提问来源于stack exchange,提问作者pc001
相关产品推荐
相关产品推荐

