与之前 getDerivedStateFromProps 中的 props 进行比较

IT技术 reactjs
2021-05-08 13:19:01

想想一个组件,它有一个 prop 'name' 和 state 'elapse'。

new Component(name) => "Hi {name}. It's been {elapse} seconds"

{elapse}当props{name}改变时应该重置为0

如果props在 10 秒时从“Alice”变为“Bob”,则消息应从

嗨,爱丽丝。已经过了 10 秒

嗨鲍勃。已经 0 秒了

  • getDerivedStateFromProps不能使用,因为{elapse}它不是 的纯函数{name},我不能返回 0,因为它可能会在重新渲染时被调用。

  • componentDidUpdate最终将更新{elapse}为 0,但在此之前,会向用户显示无效状态“Hi Bob. It's been 0 seconds”

可以getDerivedStateFromPropscomponentDidUpdate实现这个场景吗?

  1. 在许多情况下,状态不是 props 的纯函数。是否getDerivedStateFromProps仅适用于无状态功能组件?React 是否鼓励使用无状态组件?

  2. 如何在有状态组件中getDerivedStateFromProps替换componentWillReceiveProps

4个回答

如果你看看周围,你会看到你不是有这个问题的第一个-它被彻底GitHub上讨论1 2 3并在hackernews一个线程在这里推荐的解决方案是在 state 中镜像你需要检查的 props:

state = { name: "", lastTime: Date.now() }

static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.name !== prevState.name) {
        return { name: nextProps.name, lastTime: Date.now() };
    }
    return null;
}

设置初始状态记住我们传递的props是{ name:'alice' }. 但是为了getDerivedStateFromProps能够查看名称是否更改,我们必须将其镜像到我们的状态并使用prevState.name. 我们不能this在生命周期方法内部使用,因为它getDerivedStateFromPropspure

state = {time: 0, endtime: 0, name:'' } 

当组件安装时,将时钟设置为每秒递增 1。

componentDidMount() {
 this.setClock();
}

组件卸载时 clearInterval

componentWillUnmount() {
  clearInterval(this.clockCall)
}

setIntervalincrementClock每秒调用一次,每 1000 毫秒(1 秒)将计时器增加 1。

setClock = () => {
  this.setState({time: 0})
  this.clockCall = setInterval(() => {
    this.incrementClock();
  }, 1000)

}

这是我们设置时间状态并每秒递增的地方。

incrementClock = () => {
  this.setState((prevstate) => {time: prevstate.time + 1 })
}

如果名称更改,我们将时间保存在一个名为的新状态块中endtime,这就是我们用来显示的内容,hey alice its been ${this.state.endtime} seconds我们还将计时器重置为 0。

static getDerivedStateFromProps(nextProps, prevState) {
    if(prevState.name !== nextProps.name)
    return { time: 0, endtime:prevState.time };
    return null;
}

这里是你将如何使用这两个例子getDerivedStateFromProps相比,componentWillRecieveProps

class ExampleComponent extends React.Component {
  state = {
    derivedData: computeDerivedState(this.props)
  };

  componentWillReceiveProps(nextProps) {
    if (this.props.someValue !== nextProps.someValue) {
      this.setState({
        derivedData: computeDerivedState(nextProps)
      });
    }
  }
}

class ExampleComponent extends React.Component {
  // Initialize state in constructor,
  // Or with a property initializer.
  state = {};

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.someMirroredValue !== nextProps.someValue) {
      return {
        derivedData: computeDerivedState(nextProps),
        someMirroredValue: nextProps.someValue
      };
    }

    // Return null to indicate no change to state.
    return null;
  }
}

我知道这里已经有一个公认的答案,在某些情况下,可能需要将props镜像到状态,但在您的情况下,我认为您实际上想让您的组件成为“带有键的不受控制的组件”,如解释here : https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key

然后你会像这样使用它:

<Component key={name} name={name}/>

每次名称更新时,它都会呈现组件的一个新实例,因此会重新启动计数器。

从 16.3 版开始,推荐的更新状态以响应 props 更改的方法是使用新的静态 getDerivedStateFromProps 生命周期。(该生命周期在创建组件和每次接收新props时调用):参见:[链接] https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html