疯狂的 React key

发布: (2026年2月15日 GMT+8 22:42)
4 分钟阅读
原文: Dev.to

Source: Dev.to

通过 map 渲染

示例 1

export function Parent() {
  const [array, setArray] = useState([1, 2, 3, 4, 5]);

  useEffect(() => {
    setTimeout(() => {
      setArray((prev) => [6, 7, 8, 9, 10, ...prev]);
    }, 3000);
  }, []);

  return (
    <>
      {array.map((item) => (
        
      ))}
    
  );
}

export function Child({ item }: { item: number }) {
  console.log(item);
  return <>{item};
}

实验结果: 1 2 3 4 5

示例 2

export function Parent() {
  const [array, setArray] = useState([1, 2, 3, 4, 5]);

  useEffect(() => {
    setTimeout(() => {
      setArray((prev) => [6, 7, 8, 9, 10, ...prev]);
    }, 3000);
  }, []);

  return (
    <>
      {array.map((_, index) => (
        
      ))}
    
  );
}

实验结果: 6, 7, 8, 9, 10, 1, 2, 3, 4, 5

示例 3

export function Parent() {
  const [array, setArray] = useState([1, 2, 3, 4, 5]);

  useEffect(() => {
    setTimeout(() => {
      setArray((prev) => [
        ...prev.slice(0, 2),
        10,
        ...prev.slice(3, prev.length),
      ]);
    }, 3000);
  }, []);

  return (
    <>
      {array.map((item) => (
        
      ))}
    
  );
}

export function Child({ item }: { item: number }) {
  return <>{item};
}

实验结果: 10

实验 1

  • 初始状态: [1, 2, 3, 4, 5] → [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
是否使用 memokey渲染结果
未使用item6, 7, 8, 9, 10, 1, 2, 3, 4, 5
未使用index6, 7, 8, 9, 10, 1, 2, 3, 4, 5
使用 (React.memo)item6, 7, 8, 9, 10
使用 (React.memo)index6, 7, 8, 9, 10, 1, 2, 3, 4, 5

实验 2(值替换)

  • 初始状态: [1, 2, 3, 4, 5] → [1, 2, 10, 4, 5]
是否使用 memokey渲染结果
未使用item1, 2, 10, 4, 5
未使用index1, 2, 10, 4, 5
使用 (React.memo)item10
使用 (React.memo)index1, 2, 10, 4, 5

结论(实验 1·2)

  • 使用 React.memo 时,只要 key 相同且 props 未变化,子组件就不会重新渲染。
  • 不使用 React.memo 时,父组件每次重新渲染,子组件都会随之重新渲染。

实验 3(数组顺序变更与状态保持)

export function Parent() {
  const [array, setArray] = useState([1, 2, 3]);

  useEffect(() => {
    setTimeout(() => {
      setArray((prev) => prev.toReversed());
    }, 3000);
  }, []);

  return (
    <>
      {array.map((item) => (
        
      ))}
    
  );
}

export function Child({ item }: { item: number }) {
  const [text, setText] = useState("");

  return (
    <>
      {item}th textfield:
       setText(e.target.value)} />
    
  );
}

结果

  • 使用 key={item} 时:即使数组顺序被颠倒,组件的状态也会 正确映射,随顺序变化保持对应。
  • 使用 key={index} 时:顺序改变后 state 与 index 绑定,导致输入的值残留在错误的位置,顺序变更无法正常反映。

最终结论

  • 可以使用 index 作为 key,但在数组顺序可能变化的情况下不应使用
  • key 的作用是 将组件实例与状态关联,因此应使用唯一且不变的值(如 item 等),才能保证状态正确保持。
0 浏览
Back to Blog

相关文章

阅读更多 »

Inertia.js 静默破坏你的应用

TL;DR 在一个生产环境的 Laravel 12 + React 19 + Inertia v2 应用中工作了数周后,我反复遇到诊断成本高的故障模式:重叠访问可能……