React函数组件删除任务后渲染异常:State正确但列表显示错位
问题根因
你的问题完全是列表渲染使用数组下标作为key+子组件内部维护本地状态共同导致的React组件错误复用问题:
- 你在Tasks组件中遍历tasks渲染Task时,使用了数组下标
index作为组件的key属性 - 当你删除中间位置的任务后,剩余任务的数组下标会整体前移一位,React做虚拟DOM Diff时会认为下标对应的组件仍然存在,直接复用原有组件实例,不会重新创建
- 而你的Task组件内部的title、id、buckets等状态,仅在组件首次初始化时从props.task取值一次,后续props.task更新时,这些本地状态不会自动同步,导致复用的组件仍然展示旧的任务数据,就出现了「已删除任务保留、最后一个任务消失」的异常表现
解决方案
1. 优先修复key属性(必做)
将Tasks组件中渲染Task的key从数组下标替换为任务的唯一标识,也就是你接口返回的任务id:
// 原来的写法 return <Task key={index} task={task} setReload={setReload} /> // 替换为 return <Task key={task._id} task={task} setReload={setReload} />
修改后React可以通过唯一id正确识别需要删除的组件,不会错误复用其他任务的组件实例。
2. 优化Task组件的状态管理(推荐)
你的Task组件不需要把props.task的所有属性都复制到本地state,直接读取props.task的属性即可,不需要额外维护一套状态,从根源避免props和state不同步的问题:
// 不需要这一堆重复的本地状态 // const [title, setTitle] = useState(task.title) // const [buckets, setBuckets] = useState(task.buckets) // 直接用props.task取值即可 <h3 className='task-element task-title'>{task.title}</h3> <p className='task-element'>{parseBody(task.body)}</p>
如果确实需要编辑功能需要本地状态,要添加useEffect监听props.task的变化,同步更新本地状态:
useEffect(() => { setTitle(task.title) setBuckets(task.buckets) setBody(task.body) setId(task._id) // 其他需要同步的状态 }, [task])
额外调试提示
你当前代码中useEffect里setTasks(resJson.tasks)之后立刻循环打印tasks,拿到的是更新前的旧值,因为React的setState是异步更新的,调试的时候注意避免被误导。
内容的提问来源于stack exchange,提问作者Dylan Anderson
相关产品推荐
相关产品推荐

