我正在参加「掘金·启航计划」
有 A B C 三个数组,在 render 的时候分别遍历显示,如果此时 index 做 key,三个数组会产生冲突吗?
官方文档 是说: key 值在 兄弟节点 之间必须唯一。官网举的例子类似于:
const arrayA = [{ id: 1, name: 'cotwelf' }, { id: 2, name: 'xiuwen'}]
const Test = () => {
return (
<div>
<ul>
{arrayA.map((i) => <li key={i.id}>{i.name}</li> )}
</ul>
<div>
{arrayA.map((i) => <div key={i.id}>{i.id}、{i.name}</div> )}
</div>
</div>
)
}
那么问题来了,如果兄弟节点都是用数组 map 出来的,且 key 值有重复,那么会不会有什么问题?
如下例子,如果首次渲染没有问题,那我们改变一下数组 B 测试一下
const arrayA = ['cotwelf', 'xiuwen']
const Test = () => {
const [arrayB, setArrayB] = useState([...arrayA])
return (
<div>
<ul>
{arrayA.map((i, index) => <li key={index}>arrayA: {i}</li>)}
{arrayB.map((i, index) => <li key={index}>arrayB-index: {i}</li>)}
{arrayB.map((i) => <li key={i}>arrayB-i: {i}</li>)}
</ul>
<div onClick={() => {
const tempB = [...arrayB]
tempB.unshift('666') setArrayB(tempB)
}}>
change arrayB
</div>
</div>
)
}
当 arrayB 修改时,可以看到只有 arrayB map 出来的 dom 被修改了,同时,使用 index 作为 key 值的一组,list 都被更改,而使用唯一标识 i 作为 key 的另一组,只添加了新的元素,之前的 dom 并没有被修改。
首先,我们来看一下 JSX 编译后的结果
所以问题就回到,相邻的 createElement 有相同的 key 是否会相互影响
我们来看一下 createElement 做了什么。等于是下列 hello 返回的应该是个数组
function hello() {
return (<div>
{[1].map(i => <li key={i}>{i}</li>)}
{[1].map(i => <li key={i}>{i}</li>)}
</div>);
}
// 即
function hello() {
return /*#__PURE__*/ React.createElement(
"div",
null,
[1].map((i) =>
/*#__PURE__*/ React.createElement(
"li",
{
key: i
},
i
)
),
[1].map((i) =>
/*#__PURE__*/ React.createElement(
"li",
{
key: i
},
i
)
)
);
}
// 即
{
$$typeof: REACT_ELEMENT_TYPE,
type: "div",
key: null,
ref: null,
props: {
children: [
[{
$$typeof: REACT_ELEMENT_TYPE,
type: "li",
key: 1,
ref: null,
props: {
children: 1
},
_owner: owner,
}],
[{
$$typeof: REACT_ELEMENT_TYPE,
type: "li",
key: 1,
ref: null,
props: {
children: 1
},
_owner: owner,
}],
]
},
_owner: owner,
}
如果 key 重复,指的是这种情况
function hello() {
return (<div>
{[1,2].map(i => <li key={1}>{i}</li>)}
</div>);
}
function hello() {
return /*#__PURE__*/ React.createElement(
"div",
null,
[1, 2].map((i) =>
/*#__PURE__*/ React.createElement(
"li",
{
key: 1
},
i
)
)
);
}
// 即
{
$$typeof: REACT_ELEMENT_TYPE,
type: "div",
key: null,
ref: null,
props: {
children: [
[{
$$typeof: REACT_ELEMENT_TYPE,
type: "li",
key: 1,
ref: null,
props: {
children: 1
},
_owner: owner,
},
{
$$typeof: REACT_ELEMENT_TYPE,
type: "li",
key: 1,
ref: null,
props: {
children: 1
},
_owner: owner,
}],
]
},
_owner: owner,
}
既然数据结构不一样,key 值就不会相互影响。