与getDerivedStateFromProps中的先前道具相比较

时间:2018-04-08 21:37:41

标签: reactjs

想想一个具有道具名称的组件'和状态'过去'。

new Component(name) => "Hi {name}. It's been {elapse} seconds"
当道具{elapse}发生变化时,

{name}应重置为0。

如果道具改变了爱丽丝'到鲍勃'在10秒钟, 消息应该从

更改
  爱你,爱丽丝。已经10秒了

  

嗨鲍勃。这是0秒

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

  • componentDidUpdate最终会将{elapse}更新为0,但在此之前,无效状态" Hi Bob。它已经过了0秒,并向用户显示

可以getDerivedStateFromPropscomponentDidUpdate实施此方案吗?

  1. 在许多情况下,状态不是道具的纯粹功能。 getDerivedStateFromProps仅适用于无状态功能组件吗?反应是否鼓励使用无状态组件?

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

4 个答案:

答案 0 :(得分:6)

如果你环顾四周,我会发现你并不是第一个遇到这个问题的人 - 在github 1 2 3上进行了彻底的讨论。 和hackernews here中的一个帖子。建议的解决方案是镜像您需要检查状态的道具:

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

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

答案 1 :(得分:0)

设置初始状态请记住我们传递的道具是{ name:'alice' }。但是为了让getDerivedStateFromProps能够看到名称是否已更改,我们必须在我们的状态中镜像它并使用prevState.name访问它。我们无法在生命周期方法中使用this,因为getDerivedStateFromPropspure

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

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

componentDidMount() {
 this.setClock();
}

当组件卸载clearInterval

componentWillUnmount() {
  clearInterval(this.clockCall)
}

setInterval每秒会调用incrementClock,每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;
}

以下是使用getDerivedStateFromPropscomponentWillRecieveProps

进行比较的两个示例

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;
  }
}

答案 2 :(得分:0)

我知道这里已经有了一个可以接受的答案,并且在某些情况下,可能需要将props镜像到状态,但是在您的情况下,我认为您实际上是希望使组件成为“带钥匙的不受控制的组件”如此处所述: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}/>

每次更新名称时,它将呈现Component的新实例,因此将重新启动计数器。

答案 3 :(得分:-1)

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