OPY-bbt / OPY-bbt.github.io

my webpage
https://opy-bbt.github.io/
0 stars 0 forks source link

React key的作用以及原理 #6

Open OPY-bbt opened 5 years ago

OPY-bbt commented 5 years ago

Demo

Box组件中有两个子元素A和B,当点击Box元素时,我们调换两个子组件的位置。在子组件中添加了生命周期函数帮助理解,代码如下:

      class A extends React.Component {
        componentDidMount() {
          console.log('A DidMount');
        }
        componentDidUpdate() {
          console.log('A DidUpdate');
        }
        componentWillUnmount() {
          console.log('A WillUnmount');
        }
        render() {
          return e('p', {}, 'A');
        }
      }

      class B extends React.Component {
        componentDidMount() {
          console.log('B DidMount');
        }
        componentDidUpdate() {
          console.log('B DidUpdate');
        }
        componentWillUnmount() {
          console.log('B WillUnmount');
        }
        render() {
          return e('p', {}, 'B');
        }
      }

      class Box extends React.Component {
        constructor(props) {
          super(props);
          this.state = { bool: false};
        }
        render() {
          if (this.state.bool) {
            return e(
              'div',
              { onClick: () => this.setState({ bool: true }) },
              [
                e(B, {}),
                e(A, {}),
              ]
            );
          }
          return e(
            'div',
            { onClick: () => this.setState({ bool: true }) },
            [
              e(A, {}),
              e(B, {}),
            ]
          )
        }
      }

结果显而易见,输出: A DidMount B DidMount 当触发点击事件后,输出: A WillUnmount B WillUnmount A DidMount B DidMount

这里我们就可以看出来 react 是卸载了两个子组件,又按照B,A的顺序创建了组件。但是,这里完全可以直接调换一下顺序,复用之前的dom,提高性能。 于是,key就出场了。

OPY-bbt commented 5 years ago

在Box组件中,使用子组件的时候加上key。来看一下会有什么变化。修改一下Box中的render函数如下

       render() {
          if (this.state.bool) {
            return e(
              'div',
              { onClick: () => this.setState({ bool: true }) },
              [
                e(B, { key: 'B' }),
                e(A, { key: 'A' }),
              ]
            );
          }
          return e(
            'div',
            { onClick: () => this.setState({ bool: true }) },
            [
              e(A, { key: 'A' }),
              e(B, { key: 'B' }),
            ]
          )
        }

结果如下: A DidMount B DidMount B DidUpdate A DidUpdate

对组件加上key之后,react会复用之前的dom节点,根据key值来做节点的移动。注意react默认key值为index。意味着即使你没有加上key,react会使用index为默认值

OPY-bbt commented 5 years ago

使用index作为key带来的问题

参考:https://jsbin.com/wohima/edit?html,css,output

但也不是所有情况下都不可以使用index作为key,除非满足下面三个条件(如果你一定要用的话)