React 中 getDerivedStateFromProps 的用法和反模式

React 的 16.3 版本中对生命周期进行了较大的调整,这是为了开发者能正确地使用生命周期,避免误解其概念而形成反模式。html

本文将重点介绍 getDerivedStateFromProps 这个生命周期。要注意的是,React 16.3 的版本中 getDerivedStateFromProps 的触发范围是和 16.4^ 是不一样的,主要区别是在 setStateforceUpdate 时会不会触发,具体能够看这个生命全周期图react

用法

getDerivedStateFromProps exists for only one purpose. It enables a component to update its internal state as the result of changes in props.bash

从上边这句话中,咱们能够清晰知道 getDerivedStateFromProps 的做用就是为了让 props 能更新到组件内部 state 中。因此它可能的使用场景有两个:函数

  • 无条件的根据 prop 来更新内部 state,也就是只要有传入 prop 值, 就更新 state
  • 只有 prop 值和 state 值不一样时才更新 state 值。

咱们接下来看几个例子。ui

假设咱们有个一个表格组件,它会根据传入的列表数据来更新视图。spa

class Table extends React.Component {
    state = {
        list: []
    }
    static getDerivedStateFromProps (props, state) {
        return {
            list: props.list
        }
    }
    render () {
        .... // 展现 list
    }
}
复制代码

上面的例子就是第一种使用场景,可是无条件从 prop 中更新 state,咱们彻底不必使用这个生命周期,直接对 prop 值进行操做就行了,无需用 state 值类保存。code

在看一个例子,这个例子是一个颜色选择器,这个组件能选择相应的颜色并显示,同时它能根据传入 prop 值显示颜色。component

Class ColorPicker extends React.Component {
    state = {
        color: '#000000'
    }
    static getDerivedStateFromProps (props, state) {
        if (props.color !== state.color) {
            return {
                color: props.color
            }
        }
        return null
    }
    ... // 选择颜色方法
    render () {
        .... // 显示颜色和选择颜色操做
    }
}
复制代码

如今咱们能够这个颜色选择器来选择颜色,同时咱们能传入一个颜色值并显示。可是这个组件有一个 bug,若是咱们传入一个颜色值后,再使用组件内部的选择颜色方法,咱们会发现颜色不会变化,一直是传入的颜色值。htm

这是使用这个生命周期的一个常见 bug。为何会发生这个 bug 呢?在开头有说到,在 React 16.4^ 的版本中 setStateforceUpdate 也会触发这个生命周期,因此内部 state 变化后,又会走 getDerivedStateFromProps 方法,并把 state 值更新为传入的 prop。blog

接下里咱们来修复这个bug。

Class ColorPicker extends React.Component {
    state = {
        color: '#000000',
        prevPropColor: ''
    }
    static getDerivedStateFromProps (props, state) {
        if (props.color !== state.prevPropColor) {
            return {
                color: props.color
                prevPropColor: props.color
            }
        }
        return null
    }
    ... // 选择颜色方法
    render () {
        .... // 显示颜色和选择颜色操做
    }
}
复制代码

经过保存一个以前 prop 值,咱们就能够在只有 prop 变化时才去修改 state。这样就解决上述的问题。

这里小结下 getDerivedStateFromProps 方法使用的注意点:

  • 在使用今生命周期时,要注意把传入的 prop 值和以前传入的 prop 进行比较。
  • 由于这个生命周期是静态方法,同时要保持它是纯函数,不要产生反作用。

上述的状况在大多数状况下都是适用,可是这边仍是会有产生 bug 的风险。具体能够官网提供这个例子。在 One 和 Two 的默认帐号都相同的状况下,使用同一个输入框组件,在切换到 Two,并不会显示成 Two 的默认帐号。

这边解决方法有四种:

第一种是将组件改为彻底可控组件(也是状态值和方法全由父类控制);

第二种是改为彻底不可控组件(也就是组件不接受在 getDerivedStateFromProps 中经过 prop 值来改变内部状态),而后经过设置在构造函数中把 prop 传给 state 和设置 key 值来处理,由于 key 变化的时候 React 会从新渲染组件,而不是去更新组件。

第三种仍是保持上述组件模式,而后经过一个惟一 ID 来判断是否更新,而不是经过 color 值来判断。

第四种不使用 getDerivedStateFromProps,经过 ref 来把改变邮箱的方法暴露出去。

反模式

常见的反模式有两种,上边也有提到过。

  • 无条件地根据 prop 值来更新 state 值
  • 当 prop 值变化而且和 state 不同时就更新 state (会形成内部变化无效,上述也提到过)。

总结

咱们应该谨慎地使用 getDerivedStateFromProps 这个生命周期。我我的使用状况来讲,使用时要注意下面几点:

  • 由于这个生命周期是静态方法,同时要保持它是纯函数,不要产生反作用。
  • 在使用今生命周期时,要注意把传入的 prop 值和以前传入的 prop 进行比较(这个 prop 值最好有惟一性,或者使用一个惟一性的 prop 值来专门比较)。
  • 不使用 getDerivedStateFromProps,能够改为组件保持彻底不可控模式,经过初始值和 key 值来实现 prop 改变 state 的情景。

更多详细内容能够阅读官网 Blog

相关文章
相关标签/搜索