2022-10-31 14:26:37


by Sergei Gannochenko

通过谢尔盖·甘诺琴科(Sergei Gannochenko)

如何使用React钩子(How to use React hooks)

React 16.7.0 is finally out. It has no hooks on-board, but sooner or later, React Hooks will be there. So today we will have a talk so we’re ready to use it right away when it is time ?

React 16.7.0终于发布了。 它没有板载挂钩,但是迟早会有React Hooks出现。 所以今天我们将进行演讲,因此我们准备在时间适当时立即使用它吗?

Sometimes when you write your pure function component, you realize that at some moment you need to have a sort of flag there, which indicates that a modal is open, counter increased or… whatever. And then your second thought is: “oh man, now I need to migrate to React.Component”. Well, with hooks — not anymo-o-ore!

有时,当您编写纯函数组件时,您会意识到在某个时刻需要在那里放置某种标志,这表明模式已打开,计数器增加或其他。 然后您的第二个想法是:“天哪,现在我需要迁移到React.Component”。 好吧,带钩子-不是anymo-o-ore!

I’ll assume you have Node of the following versions installed: 6.14.0, 8.10.0 or greater than 9.10. If not, you can always use the Node version manager to fix that. Keep in mind though, that we will have to install all global packages in case we switch the Node version.

我假设您已安装以下版本的Node:6.14.0、8.10.0或大于9.10。 如果没有,您可以始终使用节点版本管理器来解决。 但是请记住,如果我们切换Node版本,则必须安装所有全局软件包。

This article requires that you have at least a basic knowledge of React, including the “component” and “pure function” concepts, “state” and “component lifecycle”. But even if you don’t, no worries, you will catch up during the process, it will be fun!

本文要求您至少具备React的基本知识,包括“组件 ”和“纯函数 ”的概念,“状态 ”和“组件生命周期 ”。 但是,即使您不担心也不用担心,但您会在此过程中赶上来,这将很有趣!

步骤1:样板(Step 1: The Boilerplate)

Open your terminal, as we are going to use a super-famous code generator for React applications, calledcreate-react-app:


npm install create-react-app -gcreate-react-app react-hooks

Now, we are able to see a folder called./react-hooks, so we go there and consider this to be a root of our application.


In order to actually enable hooks, we need to go to a list of versions of React By the time this article was written, the latest version with hooks enabled was16.7.0-alpha.2, so let’s install this. We also need to install a pair package calledreact-dom of exactly the same version.

为了真正启用钩子,我们需要在npmjs.com转到 React版本列表。 在撰写本文时,启用了挂钩的最新版本是16.7.0-alpha.2 ,所以让我们安装它。 我们还需要安装一个称为react-dom的完全相同版本的配对软件包。



npm install react@16.7.0-alpha.2 --savenpm install react-dom@16.7.0-alpha.2 axios --save

Don’t forget to start the application:


npm start

步骤2:useState()(Step 2: useState())

Let’s find the./src/App.js file and re-write it like this:


And this is the first kind of hooks we can use: a state hook created withuseState().Basically,useState() accepts the initial value of some value and returns an array, where the first element is a variable with the initial value, and the second one is a function which allows us to change the variable. After we callsetCounter(), the component gets re-rendered with an updated value of the counter.

这是我们可以使用的第一种钩子:使用useState()创建的状态钩子 基本上,useState()接受某个值的初始值并返回一个数组,其中第一个元素是具有初始值的变量,第二个元素是允许我们更改变量的函数。 在调用setCounter()之后 ,组件将使用计数器的更新值重新呈现。

The equivalent code without hooks would be:


But with hooks, the code is way cleaner, and it does not even rely on object-oriented programming andthis statements, which sometimes can be really cryptic to use for non-experienced JavaScript developers.


The state could be a complex object, no problem:


But according to the philosophy of hooks, it is better to define two state values instead:


This makes your code really easy to understand.


步骤3:useEffect()(Step 3: useEffect())

In the react world, aside effect is an action that is usually executed on thecomponentDidMount(), componentDidUpdate() andcomponentWillUnmount() lifecycle methods ofReact.Component. But what if we still would like to have a side effect, but with a pure function? Sure thing! Consider the code:

在React世界中,副作用是通常在React.ComponentcomponentDidMount(),componentDidUpdate()componentWillUnmount()生命周期方法上执行的动作 。 但是,如果我们仍然希望具有纯功能的副作用怎么办? 当然可以! 考虑以下代码:

The function insideuseEffect() is called on the first render and all consequent renders, which does not really make any difference between this and if we just put the code inside the component function directly.


But, wait. That is not all!

可是等等。 那还不是全部!

We could do some optimizations by tellinguseEffect() to run only when certain values have changed. Consider this:

我们可以通过告诉useEffect()仅在某些值发生更改时才运行来进行一些优化。 考虑一下:

So,useEffect() will memoize[forBatman, forJoker] value and will only re-run the effect if something changed in these arguments.


Let’s consider more use cases.


案例A:卸载后执行代码(Case A: execute code on un-mount)

What if we want to catch a moment when the component gets unmounted? All we have to do is to return a function like this:

如果我们想等一下组件卸载后该怎么办? 我们要做的就是返回这样的函数:

“SubComponent unmounted” will appear in the console as soon as you click the “One for application” button 5 times.

单击“One for application(应用程序之一 )按钮5次后,控制台中将出现“已卸载SubComponent ”。

情况B:仅在安装和卸载时运行(Case B: run only on mount and on unmount)

What we could also do is to force an effect to run only on-mount and on-unmount, by passing an empty array as a dependency:


It works because[] stays the same during all the time the component is there until it gets unmounted, no matter what.


情况C:在安装和更新时异步加载数据(Case C: load data asynchronously on mount and on update)

The last use-case I would like to demonstrate is how to do an asynchronous effect with some data load. Just to be clear, I don’t think that having logic for rendering data and logic for loading data in one place is actually a good idea. The main principle of single responsibility tells us there should be a pure dumb rendering logic and pure rich business logic, that is why I strongly encourage you to tryRedux +Saga. But I guess this is a nice topic for some other time.

我要演示的最后一个用例是如何在某些数据加载下实现异步效果。 只是要清楚一点,我不认为具有将数据渲染的逻辑和将数据加载到一个地方的逻辑实际上是一个好主意。 单一责任的主要原则告诉我们,应该有一个纯哑巴渲染逻辑和一个纯丰富业务逻辑,这就是为什么我强烈建议您尝试Redux +Saga的原因 。 但是我想这是一个不错的话题。

There are two important moments to notice:


  • we can not useuseEffect(async () =>{}), asynchronous effects are not supported (yet), but we are still able to use promises there, and

    我们不能使用useEffect(async()=> {}),尚不支持异步效果,但是我们仍然可以在那里使用promises,并且

  • we don’t want this code to run on every render, so we need to define a second argument foruseEffect() in the right way. We always ask ourselves: “What needs to be changed in order to re-run the effect?”. The good answer is “characterId”.

    我们不希望此代码在每个渲染器上运行,因此我们需要以正确的方式为useEffect()定义第二个参数。 我们总是问自己:“为了重新发挥效果需要改变什么?”。 好的答案是“characterId”。

第4步:useRef()和useMemo()(Step 4: useRef() & useMemo())

If we open the source code ofReact, we could see some other hooks available. Among them isuseRef(). We could use it in combination withuseEffect() to do some stuff. Consider the code:

如果我们打开React的源代码,我们会看到其他可用的钩子。 其中包括useRef() 。 我们可以将它与useEffect()结合使用来做一些事情。 考虑以下代码:

What it does is just sets the value of an input field and then callsfocus() as soon as the component is mounted.


Another nice one isuseMemo(). It basically allows us to memoize some value during the process of rendering.

另一个不错的是useMemo() 。 它基本上使我们能够在渲染过程中记住一些值。

Why do so? Well in case we need to calculate something reasonably heavy (heavy when rendering, huh?), or make some remote call, but only when some certain values change, we might make use ofuseMemo()thingy. It is still not as powerful as traditional ways of memoization, as it can only be used when rendering, but still…

为什么这样呢? 好吧,如果我们需要计算一些相当重的东西(渲染时很重,是吧?),或者进行一些远程调用,但是只有当某些特定值改变时,我们才可以使用useMemo()somethingy 它仍然不像传统的记忆方式那样强大,因为它只能在渲染时使用,但仍然……

第5步:深入了解(Step 5: Under the hood)

You may wonder, how does this functionality even work? I mean, components are just pure functions, how do variables preserve their scalar values between function calls? Well, for example,useState() returns an array, from which we use the first argument as a scalar. But this array can be memoized insideReact, so next time the rendering engine is here, it already knows which values to put into those scalars.

您可能想知道,该功能如何工作? 我的意思是,组件只是纯函数,变量如何在函数调用之间保留其标量值? 好吧,例如,useState()返回一个数组,我们从中使用第一个参数作为标量。 但是此数组可以在React内存储 ,因此下次渲染引擎在这里时,它已经知道要在这些标量中放入哪些值。

第6步:不要(Step 6: Don't-s)

  • First of all, hooks are still in alpha stage, the API may be changed in future, so use it in production on your own risk.

  • You can not use hooks outside a component function, it is simply how they work. But, you can makea composition of hooks.

    您不能在组件函数外部使用钩子,它只是它们的工作方式。 但是,您可以组成钩子

  • React relies on anamount andorder of how hooks appear in the component function. Sodon’t even think of wrapping those calls with conditional logic of some sort. Instead, you may put yourif-s inside a hook body.

    React依赖于挂钩在组件函数中出现的数量顺序 。 因此,甚至不要考虑使用某种条件逻辑来包装这些调用。 相反,您可以将if-s放在钩子主体内。

  • At the present moment, hooks do not work for server-side rendering. I hope this to be fixed in the final release.

    目前,钩子不适用于服务器端渲染。 我希望在最终版本中解决此问题。


Even though hooks are not available officially, they are definitely going to make our life easier, and the code way cleaner. And it is always important to have understandable code, especially when working with React.

即使没有正式可用的钩子,它们也一定会使我们的生活更轻松,并使代码更简洁。 拥有易于理解的代码总是很重要的,尤其是在使用React时。

Thanks for reading! If the article was helpful for you, don’t hesitate to share it on social media! :)

谢谢阅读! 如果文章对您有所帮助,请立即在社交媒体上分享! :)


Happy Reacting!




  • 作者:cumian8165
  • 原文链接:
    更新时间:2022-10-31 14:26:37