React - 简单说一下 key 值怎样算重复?

512 阅读1分钟

我正在参加「掘金·启航计划」

有 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 并没有被修改。

Filmage 2022-10-31_131547-filmage.gif

首先,我们来看一下 JSX 编译后的结果

image.png

所以问题就回到,相邻的 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 值就不会相互影响。