12

在项目过程中遇到了同一文件路径不同参数,路由跳转后并未调用componentWillDidMount,因此用到了React新生命周期:static getDerivedStateFromProps(nextProps, preState)并在此记录,相信下文会有您遇到的问题的解决方案!


由于文章略显繁琐,文字繁杂,附上文章脉络:
image.png


getDerivedStateFromProps的出现:

componentWillReceiveProps在React新的生命周期中被取消,这个生命周期函数是为了替代componentWillReceiveProps,所以在需要使用componentWillReceiveProps的时候,就可以考虑使用getDerivedStateFromProps来进行替代了。

getDerivedStateFromProps的功能:

我的理解:getDerivedStateFromProps这个方法名已经非常语义话了,简单翻译过来就是从Props中获得State,所以该函数的功能就是从更新后的props中获取State,它让组件在 props 发生改变时更新它自身的内部 state

getDerivedStateFromProps的参数:

nextProps:与componentWillReceiveProps的nextProps参数相同。即改变后的Props
preState:发生改变前的state中各数据的值。

getDerivedStateFromProps的触发条件:

会在调用 render 方法之前调用,即在渲染 DOM 元素之前会调用,并且在初始挂载及后续更新时都会被调用
结合下图新React生命周期理解起来会简单一些:

getDerivedStateFromProps的使用:

1.当props数据某个值发生变化时对state进行赋值:

static getDerivedStateFromProps(nextProps, preState) {
    const {match: {params: {instrumentId}}} = nextProps;
    // 此处当传入的instrumentId发生变化的时候,更新state
    if (instrumentId !== preState.instrumentId) {
        //若需要在数据变化后进行其他操作,需要在return前操作!
        return {
            instrumentId: instrumentId,
        };
    }
    return null;    // 不变化,则对于state不进行任何操作
}

2.无条件的根据 prop 来更新内部 state,也就是只要有传入 prop 值, 就更新 state
(但是如果只要props值改变,就更新state,其实直接用props的值去进行操作就可以了。)

static getDerivedStateFromProps (props, state) {
    const {match: {params: {instrumentId}}} = nextProps;
    return {
        instrumentId: instrumentId,
    }
}

3.getDerivedStateFromProps中使用this指针:

因为getDerivedStateFromProps被定义为静态方法,所以不可以直接使用this.×××,因此我们需要对类进行实例化,才使用类中定义的方法:

class InstrumentCommand extends PureComponent {
                    ......
    static getDerivedStateFromProps(nextProps, preState) {
        const {match: {params: {instrumentId}}} = nextProps;
        if (instrumentId !== preState.instrumentId) {
          new InstrumentCommand(nextProps).implementDispatch(instrumentId)
        }
    }
}
                    ......

使用getDerivedStateFromProps的遇到的问题及注意事项:

1.返回值问题:getDerivedStateFromProps方法一定要return一个值,如果不需要对state操作,只需return null;即可,不可返回undefined。
当getDerivedStateFromProps()没有明确返回任何内容时,控制台会输出警告:
2.生命周期中触发问题:如果在getDerviedStateFromProps中被操作的数据,如果在constructor初始化为null,在render中对其重新赋值,要注意需要在函数中进行判断,否则会导致报错:Cannot read properties of null (reading '......')
原因是:当刷新页面后,constructor后,生命周期中(见上图)会调用一次getDerviedStateFromProps此时并没有render()也就没有赋值,因此取到的数据为null。
代码如下:

  static getDerivedStateFromProps(nextProps, preState) {
    const {match: {params: {instrumentId}}} = nextProps;
    const {dispatch, form: {resetFields}} = nextProps;
    const {instance} = preState;
    if (instrumentId !== preState.instrumentId) {
      resetFields();
      dispatch({
        type: 'InstrumentCommandModel/cleanCommandDetail',
      });
    //我在对instance操作时,进行了一次非nul判断。
      if (instance !== null) {
        instance.setValue('');
      }
      return {
        instrumentId: instrumentId,
        editStatus: DETAIL_EDIT_STATUS.ADD,
        commandLine: '',
      }
    }
    return null;
  }

3.static getDerivedStateFromProps()方法中的三类数据:

  • nextprops:从父组件或父页面跳转时传入的props或当前也更新后的props。
  • preState:当前页State数据。
  • new 类名(nextProps):生成一个当前页初始的this指针。可以访问this数据及方法。

注意:
1.生成的是当前页面初始的this指针,如果调用方法,console.log(this.state)输出的是在constructor()中的初始值。如果你想在该函数中操作state数据或者调用对象数据中的方法时,方法如下:
①如果调用对象数据中的方法可以传入preState数据(比如:在此处笔者将state中的instance初始化为null,并在render()中使用CodeMirror组件提供的API将instance赋值为一个提供改变CodeMirror值的对象,笔者需要调用该对象中的方法,因此在static getDerivedStateFromProps()中传入preState去解构该对象,并调用其中提供的方法。)
②如果只改变state数据,getDerivedStateFromProps()本身就是为了return中直接返回更新state
image.png

2.如果实例化后,打印props为undefined,则在未在constructor()方法中传入props。

切记:如果需要在static getDerivedStateFromProps()中使用到全局this中某个对象中的方法操作数据,一定要将数据定义在state中,而不要直接定义为下图的this.instance,可以避免很多麻烦!!!
比如上文:(注意1.①)中提到的instance对象值的问题。
注意:此种情况下,建议将数据定义在state中,而不要直接this.instance=null在constructor()中定义,因为如果直接this.instance定义,就算在render中赋值后,实例化对象拿到的数据,永远是初始值null。而在state中定义的话,则只需要判断不为null的时候,就可以访问到instance对象中的方法。

constructor(props) {//不传入props,实例化后,props未undefined
    super(props);//不传入props,实例化后,props未undefined
    this.instance=null;//由实例化后的对象new 类名(nextProps)打印。
    this.state = {//由preState打印。
         instrumentId:0,
    }
}

很白的小白
145 声望125 粉丝