列表渲染与 key
列表渲染的标准动作:array.map(item => <li key={item.id}>...</li>)。map 返回新 JSX 数组,React 依次渲染——与 JS 数组方法完全一致,没有模板语法里的 v-for。
key 是 Diff 算法的“身份证”:告诉 React哪项是同一项,从而原地复用、只移动不重建。key 必须唯一且稳定,绝不要用数组下标 index——顺序变化时下标会张冠李戴,导致状态错乱与性能浪费。
- 用 map 渲染列表,别用 for 循环拼接字符串
- key 用数据的唯一 id,不用 index(除非列表只读不改顺序)
- key 只在兄弟节点间需要唯一,不同列表可以重复
HTML
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>列表与 key</title> <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> </head> <body> <div id="root"></div> <script type="text/babel"> const { useState } = React; function Todos() { const [todos, setTodos] = useState([ { id: 101, text: '学 React' }, { id: 102, text: '学 Router' }, { id: 103, text: '写项目' }, ]); function add() { // 新增插到头部:若用 index 做 key,旧项 key 全部错位 → 状态串了 const nid = Date.now(); setTodos([{ id: nid, text: '新任务 ' + nid % 100 }, ...todos]); } return ( <div style={{ padding: 16 }}> <button onClick={add}>头部插入一项</button> <ul> {todos.map(t => ( // key 放在 map 产生的最外层标签上 <li key={t.id}> #{t.id} - {t.text} <input placeholder="每项自己的输入状态" style={{ marginLeft: 8 }} /> </li> ))} </ul> </div> ); } ReactDOM.createRoot(document.getElementById('root')).render(<Todos />); </script> </body> </html>
本节要点列表渲染 = map;key 用稳定唯一 id,绝不用 index,否则顺序一变状态全串。




