Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
MrSeaWave opened this issue Sep 4, 2021 · 3 comments
Labels
JS JS React React

Comments

@MrSeaWave
Copy link
Collaborator

MrSeaWave commented Sep 4, 2021

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

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

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

详解diff

在使用key的时候应保证:

  • key 应该是唯一的

  • key不要使用随机值(随机数在下一次 render 时,会重新生成一个数字)

  • 避免使用 index 作为 key

    当子节点有 key 时,React 使用 key 来匹配原本树的子节点和新树的子节点。例如,增加一个 key 在之前效率不高的样例中能让树的转换变得高效

diff_key

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

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

image

  • 当我们通过数组来动态渲染一批组件时,react要求我们必须为每一个组件添加一个唯一的key值,不然就会在控制台出现如下warning:warning.js:33 Warning: Each child in an array or iterator should have a unique "key" prop.
  • 如果添加的key值有重复,那么重复的组件只会渲染出一个,并且react给出提示 :Child keys must be unique; when two children share a key, only the first child will be used. 第一遍渲染时 key 重复的 item ,在第二遍渲染时保留了下来。---->(React 在渲染列表时,列表元素的 Key 重复了会怎样?demo

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

  • key值只需要在同一次map中保证唯一。
  • react利用key来识别组件,它是一种身份标识标识,就像我们的身份证用来辨识一个人一样。每个key对应一个组件,相同的key react认为是同一个组件,这样后续相同的key对应组件都不会被创建。
@MrSeaWave
Copy link
Collaborator Author

MrSeaWave commented Sep 4, 2021

使用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
Copy link
Collaborator Author

不加 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 MrSeaWave added the React React label Sep 4, 2021
    @MrSeaWave MrSeaWave added the JS JS label Sep 13, 2021
    @MrSeaWave
    Copy link
    Collaborator Author

    react判断key的流程

    image

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    JS JS React React
    Projects
    None yet
    Development

    No branches or pull requests

    1 participant