Re: 新手让网页 act 起来: Day09 - 简单却不是很容易懂的 key(2)

昨天我们介绍了 key 的基本使用方式,今天我们就一起来了解为什麽需要 key 吧!

为什麽需要 key

首先,在了解为什麽之需要 key 之前,要先知道 React 在每一次的 state 更新都会触发 re-render , render 完之後会比较当次与前一次 Virtual DOM 的差异(Diff 演算),最後才会去更新 DOM 。

知道每一次 re-render 都会都会比较差异後,我们就来沙盘推演一下,在没有设置 key 的情况,React 会去怎麽做。

假设一开始我们有一个五个 li

<ul>
  <li>red</li>
  <li>blue</li>
  <li>yellow</li>
  <li>green</li>
  <li>purple</li>
</ul>
  1. 第一次更新,删掉 purple,新的结构会长这样
<ul>
  <li>red</li>
  <li>blue</li>
  <li>yellow</li>
  <li>green</li>
</ul>

我们从头开始比对,比较跟前一次的差异,发现最後一个 purple 不见了,
所以我们找出前後两者个差异就是

-      <li>purple</li>
  1. 第二次跟更新,删掉 red ,新的结构会长这样
<ul>
  <li>blue</li>
  <li>yellow</li>
  <li>green</li>
</ul>

然後一样跟前一次比对,这个时候就会发现

前一次                          新的
<ul>                           <ul>
  <li>red</li>      ->           <li>blue</li>
  <li>blue</li>     ->           <li>yellow</li>
  <li>yellow</li>   ->           <li>green</li>
  <li>green</li>    -> 
</ul>                          </ul>

结果就会变成:

-       <li>red</li>               
-       <li>blue</li>        
-       <li>yellow</li>
-       <li>green</li>

+       <li>blue</li>
+       <li>yellow</li>
+       <li>green</li>

可以仔细观察一下旁边 Elements 的变化

从我们上面的范例可以得知,React 其实没办法准确的知道使用者是删除或修改哪一个 item,但它还是必须去执行,所以这个时候,就会把 index 作为 key 来执行,这也就是为什麽不建议使用阵列的 index 作为 key 的关系。

除了效能之外,当元素有 uncontrolled component 时会造成非预期的渲染。

<html lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body>
  <div id='root'></div>
  <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
  <script src="https://unpkg.com/@babel/[email protected]/babel.js"></script>

  <script type='text/babel'>
    function App() {
      const [colors, setColors] = React.useState([
        'red',
        'blue',
        'yellow',
        'green',
        'purple'
      ])

      const removeItem = (targetItem) => {
        setColors((prev) => prev.filter(item => item != targetItem))
      }

      return (
        <ul>
          {colors.map((item, idx) => {
            return (
              <li>
                <button onClick={() => { removeItem(item) }}>x</button>
                <input type="text" defaultValue={item} />
                {item}
              </li>
            )
          })}
        </ul>
      )
    }

    ReactDOM.render(<App />, document.getElementById('root'))
  </script>
</body>

可以发现 input 的 value 并不是交给 React 来管理,所以当我们删除第一个 li 时,其实是将 red 修改成 blue , input 的 defalutValue 也确实有改,但 value 的 state 本身是交给 Html form element 管理,input 并没有整个换掉,所以 value 依然保持 red。

所以当我们在 render list 的时候要特别注意这个 list 会不会做修改,或是有没有用到 uncontrolled component ,如果有那就不能使用 index 作为 key。

当然如果不想思考这麽多,其实只要确保在 render list 都给唯一的 key 就不会有什麽问题了。

以上就是今天的介绍,有什麽问题都欢迎在下方留言。

参考资料:
https://epicreact.dev/why-react-needs-a-key-prop/


<<:  Day18 订单 -- 优惠项目

>>:  [Day9]SQL函数:单列函数

Day14 NiFi - NiFi Expression Language

今天要来介绍的是 NiFi Expression Language (以下简称NEL)。在前一篇我们...

Day30 javascript 总结

今天是最後一天,咱们今天不看程序码,来谈谈现在我们已经学习了 JavaScript,做个总结顺便想想...

[Day20] Flutter GetX routing

这篇主要讲GetX在页面切换之间的路由(上下页的前後文关系) 初步先建立一个routes的资料夹 里...

Day 02 注册 Azure 帐号与套件安装- 免费体验30天

注册 Azure 帐号与套件安装- 免费体验30天 基本起手式,能注册的先注册,能安装的先安装。 注...

Day19 将电脑接上数据机和网路线

到目前为止,我试玩过 CC: Tweaked Disk Drive、Speaker、Printer、...