首页 > 解决方案 > 为什么 getDerivedStateFromProps 是静态方法?

问题描述

我还没有在静态 getDerivedStateFromProps 上工作,所以我试图了解它。

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

为什么

   static getDerivedStateFromProps(nextProps, prevState){

   }

为什么不

   getDerivedStateFromProps(nextProps, prevState){

   }

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

标签: javascriptreactjsreact-native

解决方案


要理解 React 试图用静态方法实现什么,你应该很好地理解以下内容:

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

  1. 副作用只不过是操纵任何超出范围的数据。因此 getDerivedStateFromProps 中的副作用意味着更改其自身的局部变量以外的任何其他变量。

不会引起副作用的函数称为纯函数,在它们的参数的情况下,它们在被操作之前被克隆,从而保留这些参数指向的对象的状态。

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


  1. 在像 React 这样的库中使用自己的生命周期流来引入自定义异步代码并不是一个好主意。应在适当的时候小心插入。让我们通过分析自定义类组件的组件创建生命周期来了解原因(为了保持简短,让我们考虑它也是根元素)。

一开始 ReactDOM.render 方法调用 react.createElement() 方法调用。

react.createElement() => 调用 new 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)中完成的。

最后,render方法返回后,react.createElement()调用componentDidMount成功标记生命周期结束。既然结束了,componentDidMount 自然就成为了附加异步和不纯函数的最佳连接点。

我们必须了解的是,生命周期方法出于性能和灵活性的原因而不断调整,并且完全在 React 工程师的控制之下。它不仅适用于 React,事实上它适用于任何第三方代码的流程。因此,引入不纯函数或异步调用可能会导致问题,因为您将迫使 React 工程师小心优化。

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


  1. 另一个例子是如果 React 工程师决定使渲染调用异步。也许他们会想要合并所有的渲染调用(从父级到所有嵌套的子级)并立即异步触发它们以提高性能。

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

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


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

但是考虑到 getDerivedStateFromProps,如果先前的 props 与当前的 props 不同,则仅提供此挂钩以返回状态的更新克隆。根据这个定义,这听起来很纯粹,不需要对实例属性进行任何访问。我们来分析一下原因。

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

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

现在这并不意味着开发人员不能编写它们,而是这只是使它变得困难并迫使他们远离这种方法。


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


推荐阅读