componentWillReceiveProps 与 getDerivedStateFromProps

IT技术 javascript reactjs lifecycle
2021-05-14 10:20:14

componentWillReceiveProps 和 getDerivedStateFromProps 究竟是什么对我来说是一个微妙的问题。因为,我在使用 getDerivedStateFromProps 时遇到了一个问题:

// Component 
state = {
  myState: []
}

// Using this method works fine:

componentWillReceiveProps(nextProps) {
  this.setState({
    myState: nextProps.myPropsState
  })
}

// But using this method will cause the checkboxes to be readonly:

static getDerivedStateFromProps(nextProps,prevProps) {
  const { myPropsState: myState } = nextProps
  return {
    myState
  }
}

// And here's checkbox
<input type="checkbox" id={`someid`} 
 onChange={(e) => this.handleMethod(e, comp.myState)} 
 checked={myState.indexOf(comp.myState) > -1} />

react版本:16.4.1

3个回答

getDerivedStateFromProps不是 的直接替代品componentWillReceiveProps,纯粹是因为它在每次更新后调用,无论是状态的变化还是props的变化或父的重新渲染。

但是无论如何,简单地返回状态getDerivedStateFromProps并不是正确的方法,您需要在返回值之前比较状态和props。否则,每次更新时,状态都会重置为 props,循环继续

根据文档

getDerivedStateFromProps在调用 render 方法之前,在初始安装和后续更新时调用。它应该返回一个对象来更新状态,或者null什么都不更新。

此方法适用于状态取决于props随时间变化的罕见用例。例如,实现一个<Transition>组件来比较它的前一个和下一个孩子来决定其中的哪个进出动画可能很方便

派生状态会导致代码冗长,并使您的组件难以思考。确保您熟悉更简单的替代方案:

如果您需要执行副作用(例如,数据获取或动画)以响应 props 的更改,请改用 componentDidUpdate生命周期。

如果您只想在 prop 更改时重新计算某些数据,请改用memoization助手。

如果您想在 prop 更改时“重置”某些状态,请考虑制作组件fully controlledfully uncontrolled with a key instead.

PS注意 getDerivedStateFromProps 的参数是propsandstate和 not nextPropsandprevProps

欲了解更多详情,

为了根据 props 更改进行更改,我们需要将 prevPropsState 存储在 state 中,以便检测更改。一个典型的实现看起来像

static getDerivedStateFromProps(props, state) {
    // Note we need to store prevPropsState to detect changes.
    if (
      props.myPropsState !== state.prevPropsState
    ) {
      return {
        prevPropsState: state.myState,
        myState: props.myPropsState
      };
    }
    return null;
  }

最后,我解决了我的问题。这是一个痛苦的调试:

// Child Component

// instead of this
// this.props.onMyDisptach([...myPropsState])

// dispatching true value since myPropsState contains only numbers
this.props.onMyDispatch([...myPropsState, true])

这是因为,我有两个条件:1)复选框更改(组件)2)按下重置按钮(子组件)

按下重置按钮时,我需要重置状态。因此,在将状态分派给重置按钮的props时,我使用了一个布尔值来知道这是重置后的更改。您可以使用任何您喜欢的东西,但需要对其进行跟踪。

现在,在组件中,我在调试控制台输出后发现了一些关于 componentWillReceiveProps 和 getDerivedStateFromProps 之间差异的提示。

// Component
static getDerivedStateFromProps(props, state) {
    const { myPropsState: myState } = props
    // if reset button is pressed
    const true_myState = myState.some(id=>id===true)
    // need to remove true value in the store
    const filtered_myState = myState.filter(id=>id!==true)
    if(true_myState) {
      // we need to dispatch the changes to apply on its child component
      // before we return the correct state
      props.onMyDispatch([...filtered_myState])
      return {
        myState: filtered_myState
      }
    }
    // obviously, we need to return null if no condition matches
    return null
  }

这是我发现控制台输出的结果:

  • 每当props发生变化时,getDerivedStateFromProps 立即记录

  • componentWillReceiveProps 仅在 child 传播 props 更改后记录

  • getDerivedStateFromProps 不响应props更改(我的意思是示例代码中的调度更改)

  • componentWillReceiveProps 响应 props 的变化

  • 因此,我们需要在使用 getDerivedStateFromProps 时提供对子组件的更改。

在我需要的状态中粘贴真值的过程,因为 getDerivedStateFromProps 处理所有更改,而 componentWillReceiveProps 仅处理子组件将更改分派到 props。

顺便说一句,您可以使用自定义属性来检查它是否已更改并在 getDerivedStateFromProps 时更新值,但由于某种原因,我必须调整此技术。

我的措辞可能有些混乱,但我希望你能理解。

从react文档:

请注意,无论原因如何,都会在每次渲染时触发此方法这与 形成对比UNSAFE_componentWillReceiveProps,它仅在父级导致重新渲染时触发,而不是由于本地setState.

每次调用setState(). 因此,当您选中一个框时,该框(e) => this.handleMethod(e, comp.myState)被称为假设调用setState()以更新复选框的选中状态。但在那之后getDerivedStateFromProps()将被调用(在渲染之前)恢复该更改。这就是为什么从 props 无条件更新 state 被认为是反模式的原因