It’s very common to require some setup when a component is mounted to perform tasks like network calls. Before hooks were introduced we were taught to use functions like componentDidMount(). It is natural to look for equivalent hooks when transitioning to functional components.

在安装组件以执行诸如网络调用之类的任务时,通常需要进行一些设置。 在引入钩子之前,我们被教导要使用诸如componentDidMount()类的函数。 在过渡到功能组件时自然会寻找等效的钩子。

TL;DR, hooks and lifecycle methods are based on very different principles. Methods like componentDidMount() revolve around lifecycles and render time whilst hooks are designed around state and synchronization with the DOM.

TL; DR,挂钩和生命周期方法基于完全不同的原理。 诸如componentDidMount()类的方法围绕生命周期和渲染时间展开,而挂钩则围绕状态和与DOM的同步进行设计。

A lot of programmers assume that they can replace the behavior of componentDidMount() with useEffect(fn, []). While there don’t seem to be any major errors when using this approach, it can still lead to some app-breaking bugs. Both methods are fundamentally different, and you might not get the expected behavior you want. Programmers are not supposed to think of hooks as functions that run when a component mounts. Assuming hooks work in this fashion will hinder your understanding (and learning) of hooks.

许多程序员认为他们可以用useEffect(fn, [])代替componentDidMount()的行为。 尽管使用此方法似乎没有任何重大错误,但它仍可能导致一些破坏应用程序的错误。 两种方法本质上是不同的,并且您可能无法获得所需的预期行为。 程序员不应将挂钩视为挂载组件时运行的功能。 假设钩子以这种方式工作会阻碍您对钩子的理解(和学习)。

状态和道具的捕获方式不同 (State and props are captured differently)

Perhaps the most obvious difference is how the two methods capture state and props. This becomes especially apparent when using async methods.

也许最明显的区别是两种方法如何捕获状态和道具。 使用异步方法时,这一点尤其明显。

This component seems quite simple. Once it has mounted, it called a function which returns a promise that resolves after some time. Once that promise is resolved it then logs the current state of the name variable. Let’s try porting the same code over to a functional component.

这个组件似乎很简单。 挂载后,它调用了一个函数,该函数返回在一段时间后解析的promise。 兑现承诺后,它将记录名称变量的当前状态。 让我们尝试将相同的代码移植到功能组件上。

The above code doesn’t work properly. The useEffect() method captures the values of state and props when it is created. As a result, the console will print an empty line, even though the user could’ve typed in anything at this point. To tell React that the effect should use the most up-to-date value, you must pass dependencies directly into your effects. The same logic applies to props. In this case, effects are simpler than a class-based component, since they would also have to use the componentDidUpdate() method.

上面的代码无法正常工作。 useEffect()方法在创建状态时捕获state和props的值。 结果,即使此时用户可以输入任何内容,控制台也将打印一个空行。 要告诉React效果应该使用最新值,您必须将依赖项直接传递到效果中。 同样的逻辑适用于道具。 在这种情况下,效果比基于类的组件更简单,因为它们还必须使用componentDidUpdate()方法。

该方法在不同时间调用 (The methods are called at different times)

React can determine when state has been set synchronously within the componentDidMount() method. Let’s look at the actual lifecycle of a component:

React可以确定何时在componentDidMount()方法中同步设置状态。 让我们看一下组件的实际生命周期:

  1. The component is mounted

    组件已安装
  2. The DOM is created with the returned content from render()

    DOM是使用render()返回的内容创建的

  3. componentDidMount() is called and the state is updated

    调用componentDidMount()并更新状态

  4. The DOM is re-rendered and the content is updated

    重新渲染DOM并更新内容

One might expect that we should see a flicker between the first and second frames but that’s not the case. React detects that the state had been updated and only displays the second frame. This can be useful if a component requires the proportions of an element that can only be calculated when the DOM is rendered.

可能希望我们在第一帧和第二帧之间看到闪烁,但事实并非如此。 React检测到状态已更新,仅显示第二帧。 如果组件需要仅在呈现DOM时才能计算的元素比例,这将很有用。

Hooks and useEffect() both run after the component is mounted. The difference is that hooks are also run after the DOM content has been painted. So, if the state is updated synchronously within an effect method users will see a flicker as the first frame is replaced with the second frame.

挂接和useEffect()都在组件安装后运行。 不同之处在于,在绘制DOM内容之后也将运行钩子。 因此,如果状态在一种效果方法中同步更新,则当第一帧替换为第二帧时,用户将看到闪烁。

You can obtain the old behavior with hooks by using the useLayoutEffect() method, which is called before the content is committed to the page. However, most apps don’t need to use this hook and most programmers should stick to useEffect().

您可以使用useLayoutEffect()方法获得带有钩子的旧行为,该方法在将内容提交到页面之前被调用。 但是,大多数应用程序不需要使用此挂钩,并且大多数程序员应坚持使用useEffect()

Class-based components are designed around lifecycles and time. Functional classes instead aim to synchronize state with the DOM. Failing to shift mindsets can result in some strange quirks and bugs which could be difficult to solve without proper knowledge. In short, one should consider “based on the state, what should my component look like, and when should it re-render.” These questions will ensure that your functional components run properly.

基于类的组件是围绕生命周期和时间设计的。 相反,函数类旨在将状态与DOM同步。 无法转变思维定势会导致一些奇怪的怪癖和错误,而如果没有适当的知识,这些错误和错误可能很难解决。 简而言之,应该考虑“基于状态,我的组件应该是什么样子,以及何时应该重新渲染”。 这些问题将确保您的功能组件正常运行。

翻译自: https://medium/javascript-in-plain-english/componentdidmount-and-useeffect-are-not-the-same-heres-why-cea02f474c82

更多推荐

ComponentDidMount和useEffect不相同。 这就是为什么