【问题标题】:Compare with previous props in getDerivedStateFromProps与 getDerivedStateFromProps 中之前的 props 进行比较
【发布时间】:2018-11-08 01:53:53
【问题描述】:

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

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

{elapse} 应该在 {name} 属性发生变化时重置为 0。

如果道具在 10 秒后从“Alice”变为“Bob”, 消息应该从

嗨,爱丽丝。已经10秒了

嗨,鲍勃。 0秒了

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

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

getDerivedStateFromPropscomponentDidUpdate 可以实现这个场景吗?

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

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

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    如果你环顾四周,你会发现你不是第一个遇到这个问题的人 - 它在 github 1 2 3 和hackernews 上的一个线程中得到了彻底的讨论here。推荐的解决方案是在 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;
    }
    

    【讨论】:

    • componentWillReceiveProps 将被弃用。我认为 getDerivedStateFromProps 无法访问“this”关键字。
    • @mq7 答案已修复。现在应该可以解决您的问题。如果您有任何其他问题,请告诉我:)
    • 我不确定镜像是个好方法,但我找不到任何其他解决方案。
    • 在某些情况下可能需要镜像,但对于这种情况(可能还有许多其他人在谷歌上找到这个答案的情况)我认为更推荐的反应方式是使用不受控制的组件关键,正如我在下面的回答中所解释的那样:stackoverflow.com/a/53195052/1347649
    【解决方案2】:

    设置初始状态请记住我们传递的道具是{ 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;
      }
    }
    

    【讨论】:

    • getDerivedStateFromProps 如何访问“this”?这是一个静态方法。
    • 是的,它应该是 nextProps.name 只是一个错字,名称的状态来自 props。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 感谢您的链接。我的问题正是关于新的生命周期。
      • 我的意思是我已经知道新的生命周期了,我发布这个问题是因为我不知道在某些场景中应用新的statid方法的正确方法。
      猜你喜欢
      • 2022-06-15
      • 1970-01-01
      • 2016-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多