# 非受控组件指定key后UI错乱
所谓受控组件,是指数据交由 state
管理的组件。
# Uncontrolled Component
An uncontrolled component is a component that renders form elements, where the form element's data is handled by the DOM (default DOM behavior)
// Example - Uncontrolled component:
const { useRef } from 'react';
function Example () {
const inputRef = useRef(null);
return <input type="text" defaultValue="bar" ref={inputRef} />
}
2
3
4
5
6
7
8
# Controlled Component
In a controlled component, the form element's data is handled by the React component (not DOM) and kept in the component's state. A controlled component basically overrides the default behavior of the HTML form elements.
重现指定key后的非受控组件UI错乱问题:
代码如下
export default function App() {
const [arr, setArr] = useState(
Array(5)
.fill("")
.map((i, idx) => ({ id: idx, value: idx }))
);
const remove = useCallback(
(index) => {
setArr(arr.filter((i, idx) => idx !== index));
},
[arr]
);
const change = useCallback(
(e, index) => {
setArr(
arr.map((i, idx) => {
if (idx === index) {
return {
...i,
value: e.target.value
};
}
return i;
})
);
},
[arr]
);
return (
<div className="App">
{arr.map((item, index) => {
return (
<div key={index}>
<span style={{ marginRight: 10 }}>id:{item.id}</span>
<span>输入框:</span>
<Input
defaultValue={item.value}
onChange={(e) => change(e, index)}
/>
<DeleteOutlined onClick={() => remove(index)} />
</div>
);
})}
</div>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
在非受控状态下的Input组件,从被删掉的位置开始,后续的所有值都发生了错乱。我们从react如何进行更新的角度来分析,为什么会出现这样的差异。
在数据发生变化时,react会进行dom diff,找出最小的改动再应用到真实的dom上。在通过遍历数组再生成节点的场景中,key 在其中发挥了很重要的作用。
在本例中,用index作为key ,删除第二项后,react对比新旧dom树会以为key=4
这项被删除了(少了一项),从而渲染时仅保留原有前四项,但因为Input组件数据并不绑定state,所以展示旧的前四条数据,于是造成了“删除任意一条,都只能删除最后一行”的局面。