React数组元素删除后子组件内容不匹配的原因排查
React列表删除后子组件内容与标题不匹配的原因分析
问题描述
在React组件中维护things数组,遍历数组时在父组件的div中展示元素名称,并将每个元素传入子组件展示详情。
问题现象:删除数组中除最后一个元素外的任意元素时,父组件的对应标题会正确消失,但子组件内容未同步更新,反而呈现出“最后一个元素被删除”的视觉效果——内容整体上移,导致标题与子组件展示的内容完全不匹配。
补充说明:子组件需要维护自身状态,实际场景中用于实现更新传入对象的表单,示例中简化移除了更新逻辑。
主组件代码
import { useState, useEffect } from "react"; import InnerComponent from "./InnerComponent"; import Thing from "./Thing"; import "./styles.css"; export default function App() { const [things, setThings] = useState<Thing[]>([]); useEffect(() => resetThings(), []); const resetThings = () => { setThings([ { name: "dog", num: 5 }, { name: "cat", num: 7 }, { name: "apple", num: 11 }, { name: "book", num: 1} ]); }; const onDeleteThing = (indexToDelete: number) => { const newThings = [...things]; newThings.splice(indexToDelete, 1); setThings(newThings); }; return ( <div className="App"> {things.map((thing, index) => ( <div key={`${index}`} className="thing-container"> <h2>{thing.name}</h2> <InnerComponent thing={thing} index={index} onDelete={onDeleteThing} /> </div> ))} <div> <button onClick={resetThings}>Reset Things</button> </div> </div> ); }
子组件代码
import { useEffect, useState } from "react"; import Thing from "./Thing"; interface InnerComponentParams { thing: Thing; index: number; onDelete: (indexToDelete: number) => void; } export const InnerComponent: React.FC<InnerComponentParams> = ({ thing, index, onDelete }) => { const [name, setName] = useState(thing.name); const [num, setNum] = useState(thing.num); return ( <div> <div>Name: {name}</div> <div>Num: {num}</div> <div> <button onClick={(e) => onDelete(index)}>Delete Me</button> </div> </div> ); }; export default InnerComponent;
问题原因
1. 列表key使用数组索引导致组件错误复用
React依赖key属性识别列表元素的唯一性,以此决定是复用现有组件实例还是创建新实例。你当前使用数组的index作为key,当删除数组中间元素时,后续元素的索引会发生偏移:
- 例如删除索引1的"cat"后,原索引2的"apple"会变为新的索引1,原索引3的"book"变为新的索引2。
- React会认为
key为1、2的组件已经存在,直接复用原有组件实例,仅更新它们的props,不会重新初始化组件状态。
2. 子组件状态未随props变化同步更新
子组件的name和num状态仅在组件首次挂载时,通过useState用初始props值初始化。之后即使父组件传入的thing props发生变化,子组件也不会自动更新自身状态。结合上述组件复用问题,就出现了标题与内容不匹配的现象:
- 比如删除索引0的"dog"后,新数组的第一个元素是"cat",对应
key为0。React会复用原来key=0的子组件实例(该实例的状态还是"dog"的信息),父组件标题显示"cat",但子组件仍展示"dog"的内容,最终导致错位。
内容的提问来源于stack exchange,提问作者Creature
相关产品推荐
相关产品推荐

