React16这个版本,废弃了一些声明周期函数,同时也新增了一些生命周期函数。这一篇先说一下新增的声明周期函数getDerivedStateFromProps。
getDerivedStateFromProps作为componentWillReceiveProps的替代品出现,但是它与componentWillReceiveProps也有很多不同点
Derived State(衍生状态)
当组件的props改变而引发state改变,这个state就被称为是Derived State。
1 | //parent component |
1 | //children component |
父组件传入的productId不同,子组件的id也会不一样,而这个id就是Derived State
static function
getDerivedStateFromProps这个生命周期函数是静态类型的,也就是说无法在其内部调用this
参数
getDerivedStateFromProps(nextProps, prevState){}
它的两个参数分别是变化后的props和当前的state,因为它是静态方法,所以可以直接对state进行赋值,相当于调用setState方法,但是不管改不改变state都要有返回值,否则报错。其返回值为Object,返回null或者基本类型都相当于没有变化。
1 | getDerivedStateFromProps(nextProps, prevState){ |
调用时机
调用时机在16.3与16.4这两个版本有区别:
16.3:只有在props改变的时候,才会执行
16.4:任何一次render之前,都会执行(new props, setState, forceUpdate)
可以看出,如果任何一次render之前都需要执行,非常耗性能,所以这个生命周期函数能不用尽量不要使用。如果必须使用,最好要有条件判断
开发时遇到的问题以及解决方案
前段时间做项目的时候,遇到一个联动功能,当左侧的输入框中输入完信息后,也就是blur后右侧的下拉菜单要变为对应值,右侧是下拉菜单也是一个独立的组件:
刚开始的想法是,只要改变传入的props,然后在下拉组件内的getDerivedStateFromProps函数中设置为对应的值就可以,大致代码如下:
1 | //parent component |
1 | //ChildSelect |
看起来没什么问题,但是这样写会很麻烦,需要控制两个组件,而且在selectOnChange方法内有setState,这样每次选择选项的时候,都要走一遍getDerivedStateFromProps方法,虽然做了判断处理,但也相当于是无用的操作。如果以后扩展的功能里需要改变上面的defaultVal,那里面涉及的问题会更多。
React官网的建议是,用key值来代替getDerivedStateFromProps方法,也就是如果key改变了,子组件也会重新渲染,这样就不用在子组件内判断props来改变状态。
更改后的代码:
1 | //parent component |
1 | //ChildSelect |
父组件增加了key,其值为defVal,子组件内获取到props进行设置,当defVal变化后,子组件重新渲染,而当选择子组件的选项时,也不会受到影响,同时也具有可扩展性。
总结
虽然新增的声明周期钩子函数代替之前版本的函数,但里面也有很多不可避免的问题,所以还是那句话,也是React官方的建议,getDerivedStateFromProps是不常用的声明周期函数,如果不是必须,还是不要随意使用,否则可能是在滥用Derived State。