★ key

作者: 行走的蛋白质 | 来源:发表于2020-04-29 19:23 被阅读0次

    key 是什么,能做什么,怎么做的?


    • key 是给每一个 vnode 的唯一 id 标识,依赖它我们可以 更准确、更快速 的找到 oldvnode 中对应的 vnode 节点。
      • 更准确:在 sameNode 函数中,根据 key 可以避免 就地复用
        • 就地复用:数组渲染调换位置,没有 key 节点位置不变内容更新,有 key 节点位置互换
      • 更快速:map 比遍历更快:利用 key 的唯一性生成 map 映射查找对应节点,比遍历方式查找更快速
        • map 映射是基于 hash 值的线性查找时间复杂度为 O(1),而数组遍历时间复杂度为 O(n)

    作用

    • key 的作用主要是为了高效的更新虚拟 DOM。
    • Keys 是 React 中用于追踪列表中哪些元素被修改、被添加、被移除等的辅助标志
    • 在开发中我们要保证 key 在同级元素中具有唯一性
    • 在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是新创建的还是被移动而来的元素,从而减少不必要的元素重渲染。
    • React 还需要借助 Key 来判断元素与本地状态的关联关系

    实例描述

    //this.state.users内容
    this.state = {
       users: [{id:1,name: '张三'}, {id:2, name: '李四'}, {id: 2, name: "王五"}],
       ....//省略
    }
    render() {
       return(
           <div>
               <h3>用户列表</h3>
               {this.state.users.map(u => <div key={u.id}>{u.id}:{u.name}</div>)}
           </div>
       )
    }
    
    • 效果:
      上面代码在 dom 渲染挂载后,用户列表只有 张三李四 两个用户,王五 并没有展示处理,主要是因为 react 根据 key 认为 李四王五 是同一个组件,导致第一个被渲染,后续的会被丢弃掉。
    • 这样,有了 key 属性后,就可以与组件建立了一种对应关系,react 根据 key 来决定是销毁重新创建组件还是更新组件。
      • key 相同,若组件属性有所变化,则 react 只更新组件对应的属性;没有变化则不更新。
      • key 值不同,则 react 先销毁该组件 (有状态组件的 componentWillUnmount 会执行),然后重新创建该组件(有状态组件的 constructor 和 componentWillUnmount 都会执行)

    渲染数组中 key 存在的必要性

    • 从 babel 转换后 React.createElement 中的代码可以看出,其它元素之所以不是必须需要 key 是因为不管组件的 state 或者 props 如何变化,这些元素始终占据着 React.createElement 固定的位置,这个位置就是天然的 key。而由数组创建的组件可能由于动态的操作导致重新渲染时,子组件的位置发生了变化。

    渲染数组 index 作为 key 的实践

    • 在 list 数组中,用 key 来标识数组创建子组件时,若数组的内容只是作为纯展示,而不涉及到数组的动态变更,其实是可以使用 index 作为 key 的。
    • 但是,若涉及到数组的动态变更,例如数组新增元素、删除元素或者重新排序等,这时 index 作为 key 会导致展示错误的数据。
    {this.state.data.map((v,idx)=><Item key={idx} 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>
    
    • 组件重新 render 得到新的虚拟 dom;
    • 新老两个虚拟 dom 进行 diff,新老版的都有 key=0 的组件,react 认为同一个组件,则只可能更新组件;
    • 然后比较其 children,发现内容的文本内容不同(由 a--->c),而 input 组件并没有变化,这时触发组件的 componentWillReceiveProps 方法,从而更新其子组件文本内容;
    • 因为组件的 children 中 input 组件没有变化,其又与父组件传入的 props 没有关联,所以 input 组件不会更新(即其 componentWillReceiveProps 方法不会被执行),导致用户输入的值不会变化。

    相关文章

      网友评论

          本文标题:★ key

          本文链接:https://www.haomeiwen.com/subject/wyggwhtx.html