z-memo / interview

我们缺的从来都不是前端/后端工程师,而是工程师(或者那些会系统思考,并总是想着解决问题的人)
27 stars 3 forks source link

写 React 项目时为什么要在列表组件中写 key,其作用是什么 #1

Open MrSeaWave opened 3 years ago

MrSeaWave commented 3 years ago

元素key属性的作用是用于判断元素是新创建的还是被移动的元素,从而减少不必要的元素渲染

React 官网所说:key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。

使用key是react性能优化的手段,在一系列数据最前面插入元素,如果没有key的值,则所有的元素都需要进行更换,而有key的情况只需要将最新元素插入到前面,不涉及删除操作

详解diff

在使用key的时候应保证:

diff_key

当没有 key 的时候,如果中间插入一个新节点,Diff 过程中从第三个节点开始的节点都是删除旧节点,创建新节点。当有 key 的时候,除了第三个节点是新创建外,第四和第五个节点都是通过移动实现的。

react React 源码深度解读(十):Diff 算法详解 解析:Daily-Interview-Question/issues/1

image

https://www.jianshu.com/p/e639dbc325ef

MrSeaWave commented 3 years ago

使用index 作为key 可能会出现的问题 https://juejin.cn/post/6967626390380216334#heading-2

更多 demo

{this.state.data.map((v,index) => <Item key={index} v={v} />)}
// 开始时:['a','b','c']=>
<ul>
    <li key="0">a <input type="text"/></li>
    <li key="1">b <input type="text"/></li>
    <li key="2">c <input type="text"/></li>
</ul>

// 数组重排 -> ['c','b','a'] =>
<ul>
    <li key="0">c <input type="text"/></li>
    <li key="1">b <input type="text"/></li>
    <li key="2">a <input type="text"/></li>
</ul>

key-index

MrSeaWave commented 3 years ago

不加 key 再渲染时会更快。

验证,渲染 10_000 个

  • 标签,在componentWillUpdate标记 render 开始时间,componentDidUpdate生命周期里打印时间差。

    总共打印两次结果,第一次componentDidMount时更新 state,第二次间隔 1 秒更新 state 再打印。

    import React, { Component } from 'react';
    import uuid from 'uuid/v1';
    
    let time = 0
    
    class App extends Component {
      state = {
        list: []
      }
    
      componentDidMount() {
        const list = Array.from({length: 1000}).fill(null).map(() => ({
          value: uuid(),
          key: uuid()
        }));
        this.setState({list})
    
        setTimeout( () => {
          const list = Array.from({length: 1000}).fill(null).map(() => ({
            value: uuid(),
            key: uuid()
          }), 1000);
          this.setState({list})
        })
      }
    
      componentWillUpdate() {
        time = +Date.now()
      }
    
      componentDidUpdate() {
        console.log(+Date.now() - time)
      }
    
      render() {
        const {list} = this.state;
        return (
          <div className="App">
            <ul>
              {list.map((item,idx) => (
                <li>{item.value}</li>
                // <li key={item.key}>{item.value}</li>
              ))}
            </ul>
          </div>
        );
      }
    }

    不加 key 的结果:

    image

    加 key 的结果:

    image

  • MrSeaWave commented 3 years ago

    react判断key的流程

    image