componentWillUpdate/componentDid

2019-04-02  本文已影响0人  罗坤_23333

基础

React.Component

1.state更新或者父组件state更新都会触发

React.PureComponent

1.state更新或者父组件传递过来的props有更新

React.PureComponent with Context

1.如果不注册contextType,则与React.PureComponent一致。
2.如果注册了contextType,则与React.Component一致

如果在视图中使用context value,当context value有改变时,视图会更新,但不会触发componentWillUpdate/componentDidUpdate

不注册contextType

parent component

import React from 'react'

const MyContext = React.createContext({});

class Parent extends React.Component {
    state={
      num:1
    };

    add=()=>{
      let num = this.state.num;
      num+=1;
      this.setState({num:num})
    };

    render(){
        return (
            <MyContext.Provider value={this.state}>
              <div>
                  <div>{this.state.num}</div>
                  <button onClick={this.add}>+1s</button>
                  <Child />
              </div>
            </MyContext.Provider>
        )
    }
}

export default Parent

child component

class Child extends React.PureComponent {
    componentWillUpdate(nextProps, nextState, nextContext) {
        console.log('componentWillUpdate',nextProps, nextState, nextContext)
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log('componentDidUpdate',prevProps, prevState, snapshot)
    }

    render(){
        return (
            <MyContext.Consumer>
                {(state)=>
                    <div>
                        I'm child component,
                        <p>
                            this num from parent :{state.num}
                        </p>
                    </div>
                }
            </MyContext.Consumer>
        )
    }
}

//如何注册contextType
//Child.contextType = MyContext;

进阶

SCU shouldComponentUpdate

shouldComponentUpdate返回true时,React必须走到该节点并检查它们。
diff后发现元素不相等时,React必须更新DOM,
diff没有变化时,利用thunk机制可以使它不必更新DOM。

但是PureComponent中,shouldComponentUpdate只是对stateprops的值进行浅对比,比如下方代码:

class ListOfWords extends React.PureComponent {
    render() {
        return <div>{this.props.words.join(',')}</div>;
    }
}

export default class WordAdder extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            words: ['marklar'],
        };
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
        // This section is bad style and causes a bug
        const words = this.state.words;
        words.push('marklar');
        this.setState({words: words});
    }

    render() {
        return (
            <div>
                <button onClick={this.handleClick} />
                <ListOfWords words={this.state.words} />
            </div>
        );
    }
}

点击button之后,ListOfWords组件并不会更新。

因此避免此问题的最简单方法是避免你正在使用的stateprops值发生突变(mutating),而是比如这样返回一个新值/新址:

- words.push('marklar');
- this.setState({words: words});
+ this.setState({words: words.concat('marklar')});
// 或者 ES6写法
+ this.setState({words: [...words,'marklar']})

PS:这也是为什么React新版文档内变量全部换成const声明了

优化手动对比shouldComponentUpdate

1.有时组件需要选择性更新,而不能完全依赖PureComponent,经常会这么写:

shouldComponentUpdate(nextPrpops) {
  return JSON.stringify(nextPrpops.data) !== JSON.stringify(this.props.data)
}

只有在this.props.data数据被改变时才更新,这样写在小数据场景下本身是没有问题的,
但是如果在大数据的场景下可能会有问题,使用JSON.stringify暴力转译会非常耗时。


2.如果第一条的id不一样就表示数据变化了行不行,显然在某种情况下是存在的,但不够严谨。

shouldComponentUpdate(nextPrpops) {
  return nextPrpops.data[0].id !== this.props.data[0].id
}



3.将data的比对转换成current的比对

shouldComponentUpdate(nextPrpops) {
  return nextPrpops.current !== this.props.current
}



4.给一个requestId跟踪data,后面就只比对requestId

this.setState({
  data,
  requestId: guid()
})

shouldComponentUpdate(nextPrpops) {
  return nextPrpops.requestId !== this.props.requestId
}



上面的写法可能都有问题,但主要想说的是写代码的时候可以想想是不是可以“将复杂的比对,变成简单的比对

自定义shallowEqual函数

function shallowEqual(objA: mixed, objB: mixed): boolean {
  // 第一关:基础数据类型直接比较出结果
  if(is(objA, objB)) {
    return true
  }

  // 第二关:只要有一个不是对象数据类型就返回false
  if(
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null ||
   ){
     return false
   }
  
  // 第三关:如果两个都是对象类型,比较两者的属性数量
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);
  if (keysA.length !== keysB.length) {
    return false;
  }

  // 第四关:比较两者的属性是否相等,值是否相等
  for (let i = 0; i < keysA.length; i++) {
    if (
      !hasOwnProperty.call(objB, keysA[i]) ||
      !is(objA[keysA[i]], objB[keysA[i]])
    ) {
      return false;
    }
+  }else {
+    if(!deepEqual(objA[keyA[i]], objB[keysA[i]])){
+      return false
+    }
  }

   // 默认返回true
   return true
}

shallowEqual函数源代码:react/package/shared/shallowEqual.js

上一篇 下一篇

猜你喜欢

热点阅读