为什么getDerivedStateFromProps是静态方法?

时间:2018-10-19 04:53:56

标签: javascript reactjs react-native

我还没有研究静态的getDerivedStateFromProps,所以我想了解它。

我了解React通过引入一种称为静态getDerivedStateFromProps()的新生命周期方法,在React v16 +中已弃用componentWillReceiveProps。好的,但是想知道为什么React已经改为静态方法而不是普通方法。

为什么

   static getDerivedStateFromProps(nextProps, prevState){

   }

为什么不

   getDerivedStateFromProps(nextProps, prevState){

   }

我无法理解为什么它是静态方法。

5 个答案:

答案 0 :(得分:4)

根据对此Proposal的描述:

  

此提案旨在降低书写风险   异步兼容的React组件。

     

它通过消除许多<sup>1</sup>潜在的陷阱来做到这一点   当前的API,同时保留API的重要功能   启用。我相信这可以通过以下组合来实现:

     
      
  1. 选择目的明确,用途有限的生命周期方法名称。

  2.   
  3. 将某些生命周期设为静态,以防止不安全地访问实例属性。

  4.   

还有here

  

使用静态方法替换易于出错的渲染阶段生命周期挂钩   使编写与异步兼容的React组件更容易。

最终,经过大量讨论,也正式描述了使用静态方法的目标here

  

该提案的目标是降低写作风险   异步兼容的React组件我相信可以实现   通过消除当前API中的许多潜在陷阱   保留API支持的重要功能。可以做到   通过以下组合:

     
      
  1. 选择目的明确,用途有限的生命周期方法名称。

  2.   
  3. 将某些生命周期设为静态,以防止不安全地访问实例属性。

  4.   
     

不可能检测或预防所有副作用(例如突变)   全局/共享对象)。

答案 1 :(得分:1)

您不应使用该方法接触任何内部数据,因此将其定义为静态。这样一来,您就无法触摸任何物体,并且唯一可以做的就是使用提供的上一个状态和下一个道具来做任何事情。

答案 2 :(得分:1)

getDerivedStateFromProps是一个新的API,已被引入,以便在发布异步渲染作为功能时可扩展。根据{{​​3}},

  

选择此方法为静态方法以帮助确保纯度,即   很重要,因为它会在可中断阶段触发。

在render方法之后移动所有不稳定的事物和副作用的想法。在可中断的阶段访问组件实例变量可能会导致人们使用它具有各种副作用,从而导致异步渲染不一致

答案 3 :(得分:1)

要了解React试图通过静态方法实现的目标,您应该对以下内容有充分的了解:

  1. 副作用
  2. 为什么在componentDidMount钩子之前,异步代码被认为是一种不好的方法
  3. 异步渲染
  4. 静态方法如何防止不纯和异步编码

  1. 副作用不过是处理超出范围的任何数据。因此,getDerivedStateFromProps中的副作用意味着将更改除其自身局部变量之外的任何其他变量。

不会产生副作用的函数称为纯函数,就其参数而言,它们在操作之前就被克隆了,从而保留了这些参数所指向的对象的状态。

这些函数仅从其范围内返回修改后的值,调用者可以使用返回的数据来决定操作的过程。


  1. 在像React这样的具有自己生命周期流的库中引入自定义异步代码并不是一个好主意。应在适当的时候仔细插入。让我们通过分析自定义类组件的组件创建生命周期来理解其原因(为简短起见,我们将其视为根元素)。

在开始时,ReactDOM.render方法将调用react.createElement()方法调用。

react.createElement()=>调用新的ClassElement(props)构造函数=>返回ClassElement实例。

构造函数调用后,react.createElement()调用ClassElement.getDerivedStateFromProps(props)方法调用。

上述方法返回后,react.createElement()调用instance.render()方法。

(可以跳过)

  

此后跟着其他同步调用,例如与   虚拟DOM和更新实际DOM等,并且没有提供挂钩   利用这些电话(主要是因为没有强烈的需求)。关键   这里要注意的是javascript执行,真正的DOM更新和   UI绘画-全部-在浏览器的单个线程中进行,因此   迫使它们同步。这是您可以写作的原因之一   同步的东西:

let myDiv = document.getElementbyID("myDiv");
myDiv.style.width = "300px"; // myDiv already holds a reference to the real DOM element
console.log(myDiv.style.width); // the width is already set!
     

因为您在每个语句的结尾都知道   先前的语句在DOM和浏览器窗口中完成(UI I   )。

最后,在render方法返回后,react.createElement()调用componentDidMount来成功标记生命周期的结束。 从头开始,componentDidMount自然是连接异步函数和不纯函数的最佳结合点。

我们必须了解的是,出于性能和灵活性的原因,生命周期方法会不断调整,并且完全受React工程师的控制。这不仅与React有关,实际上与任何第三方代码的流程有关。因此,引入不纯函数或异步调用可能会导致问题,因为您将迫使React工程师对其优化保持谨慎。

例如如果React工程师决定在单个生命周期流中两次或多次运行getDerivedStateFromProps,则不纯函数和异步调用都会被触发两次或更多次,从而直接影响应用程序的某些部分。但是对于纯函数来说这不是问题,因为它们仅返回值,并且由React工程师决定多个getDerivedStateFromProps调用中的过程(它们可以简单地丢弃所有返回的值,直到最后一次调用并利用最后一个)。


  1. 再一个例子是,如果React工程师决定使渲染调用异步。也许他们想合并所有渲染调用(从父级到所有嵌套子级)并触发一次异步地提高性能。

现在,这意味着在渲染方法中或之前编写的异步调用(例如在构造函数或getDerivedStateFromProps中)可能会干扰渲染过程,因为异步过程完成过程具有不可预测性。一个可能比另一个更早或更晚完成,从而意外地触发它们各自的回调。这种不可预测性可能会以多种呈现方式,不可预测的状态等形式反映出来。

重要的是,这两个想法都不只是示例,而是由React工程师表示为可能的未来优化方法。在这里阅读:https://stackoverflow.com/a/41612993/923372


  1. 尽管如此,React工程师仍然知道那里的开发人员仍然可以编写异步代码或不纯函数,并劝阻他们将生命周期方法之一设为静态。 getSnapshotBeforeUpdate,componentDidMount和componentDidUpdate方法不能是静态的,因为它们需要访问实例属性,例如this.state,this.props,其他自定义事件处理程序等。(构造函数对其进行初始化,render使用它们来控制UI逻辑,以及其他生命周期方法需要将它们与早期状态进行比较)

但是考虑到getDerivedStateFromProps,仅当先前的道具与当前的道具不同时,才提供此钩子以返回状态的更新克隆。按照这个定义,这听起来很纯粹,不需要任何对实例属性的访问。让我们分析一下原因。

要使此钩子正常工作,开发人员首先需要将先前的道具存储在实例状态(例如,在构造函数调用中)。之所以如此,是因为getDerivedStateFromProps接收实例状态以及新的prop作为参数。然后,开发人员可以继续比较所需的属性并返回状态的更新后的副本(无需访问this.props或this.state)。

通过将getDerivedStateFromProps设置为静态,React不仅迫使您编写纯函数,而且由于您无法从此方法访问任何实例,因此也使编写异步调用变得困难。异步调用将提供一个回调,该回调很可能是实例方法。

现在,这并不意味着开发人员无法编写它们,而只是增加了难度,并迫使他们远离此类方法。


一个简单的经验法则是在第三方引发的流量期间避免不纯和异步功能的方法。您只应在此类流量结束时引入此类方法。

答案 4 :(得分:1)

getDerivedStateFromProps 的存在仅是为了使组件能够根据prop的更改来更新其内部状态。由于我们仅基于道具更新状态,因此没有理由比较nextProps和this.props。这里我们应该只比较下一个道具和先前的状态,如果状态和道具不同,则更新状态,否则不应该更新。

如果将this.props与下一个props进行比较,则需要存储旧的props值,这会影响性能。保留过去的价值的副本称为记忆力。为避免误用“此” 存储,将 getDerivedStateFromProps 设为静态

我们也可以将以上原因视为 componentWillReciveProps 折旧的原因。