您的位置:首页 > Web前端 > React

通过构建Paint App学习React Hooks

2020-08-20 18:24 736 查看 https://blog.csdn.net/cumi7754

According to people in the know, React Hooks are hot, hot, hot. In this article, we follow Christian Jensen's 14-part tutorial to find out about the basics of this new feature of React. Follow along to find out more!

据知情人士称,React Hooks很热,很热。 在本文中,我们将按照Christian Jensen的14部分教程来了解React这个新功能的基础。 继续了解更多!

介绍 (Intro)

Hooks are new to the React library and allow us to share logic between components and make them reusable.

钩子是React库的新增功能,它使我们能够在组件之间共享逻辑并使它们可重用。

In this course, we will be building a paint app similar to Microsoft Paint, which will allow us to name our project, switch out colors, get a new batch of colors and of course paint.

在本课程中,我们将构建一个类似于Microsoft Paint的Paint应用程序,这将使我们能够为项目命名,切换颜色,获得新的一批颜色,当然还有Paint。

Scrimba allows you to pause screencasts at any time and play with the code. It's a great way to learn by doing!

Scrimba允许您随时暂停截屏视频并播放代码。 这是边干边学的好方法!

先决条件 (Prerequisites)

The course assumes some prior knowledge of ES6, JSX, State and Props, but no worries, we've got you covered - check out our Scrimba articles by hitting the links above.

本课程假定您具有ES6JSX,状态和道具的一些先验知识 ,但是不用担心,我们已经为您覆盖了-点击上面的链接,查看我们的Scrimba文章。

If you are completely new to React, be sure to check out our Scrimba React course

如果您是React的新手,请务必查看我们的Scrimba React课程

useState
第1部分 (
useState
- Part 1)

First, we give our application a way to manage state using

useState
.

首先,我们为应用程序提供了一种使用

useState
管理状态的方法。

In our

<Playground.js />
component, we declare a component called
<Playground />
and create buttons to increment and decrement it. We then give
useState
an argument of (0) and use state restructuring to get
state
and
setState
(the function which updates the state) from our
useState
function. These are now renamed to
count
and
setCount
. We then render our count in the browser.

在我们的

<Playground.js />
组成部分,我们宣布了一个名为组件
<Playground />
并创建按钮来递增和递减它。 然后,将
useState
的参数
useState
(0),并使用状态重组从
useState
函数中获取
state
setState
(更新状态的函数)。 现在将它们重命名为
count
setCount
。 然后,我们在浏览器中呈现计数。

Lastly, we render buttons which update the count using an inline function which will be triggered on the click.

最后,我们渲染按钮,该按钮使用嵌入式功能更新计数,该功能将在单击时触发。

To ensure our count is accurate, we pass a function to our

setState
function instead of a value. This function takes the current state as its argument, which is then updated:

为了确保计数准确,我们将一个函数而不是值传递给

setState
函数。 该函数将当前状态作为其参数,然后对其进行更新:

import React, { useState } from "react";
import randomColor from "randomcolor";

export default function Playground() {
const [count, setCount] = useState(0);
return (
<div>
{count}
<button onClick={() => setCount((currentCount) => currentCount - 1)}>
-
</button>
<button onClick={() => setCount((currentCount) => currentCount + 1)}>
+
</button>
</div>
);
}

If you're worried about the performance of inline functions, take a look a this blog.

如果您担心内联函数的性能,请访问博客。

useState
第2部分 (
useState
- Part 2)

Now we add our name input to the

<Name.js />
component so the user can name their project.

现在,我们将名称输入添加到

<Name.js />
组件中,以便用户可以命名其项目。

To set up

<Name.js />
with a
useState
Hook, we need to import the Hook with a named import and then set our state up. Our state will be
name
and we will update it with setName. We then call
useState
and pass in an empty string as our default state value.

要使用

useState
Hook设置
<Name.js />
,我们需要使用命名的import导入Hook,然后设置状态。 我们的状态将是
name
,我们将使用setName对其进行更新。 然后,我们调用
useState
并传入一个空字符串作为默认状态值。

We now need an input element with four properties. These are:

现在,我们需要一个具有四个属性的输入元素。 这些是:

  • value
    , which will always be the state
    name
    from above

    value
    ,它始终是上方的州
    name

  • onChange
    , which will use
    setState
    inline to update
    name
    by passing the value into
    setState

    onChange
    ,将使用
    setState
    内嵌到更新
    name
    由传递值到
    setState

  • onClick
    which uses setSelectionRange which takes a start index of 0 and end index of the length of the string to select the entire name, making it easier for the end-user to change the name.

    onClick
    使用setSelectionRange,它采用起始索引0和字符串长度的终止索引来选择整个名称,从而使最终用户更容易更改名称。

  • placeholder
    , which we set to 'Untitled'.

    placeholder
    ,我们将其设置为“无标题”。

import React, { useState } from "react";

export default function Name() {
const [name, setName] = useState("");
return (
<label className="header-name">
<input
value={name}
onChange={(e) => setName(e.target.value)}
onClick={(e) => e.target.setSelectionRange(0, e.target.value.length)}
placeholder="Untitled"
/>
</label>
);
}

We can now name our project and select the name to reset it with just one click:

现在,我们可以命名我们的项目,只需单击一下即可选择要重置的名称:

useEffect
(
useEffect
)

Currently, our Playground.js component is simply rendering a counter where can increment or decrement the count. Now we will update this so that every time the count is changed, the color of something is also changed.

当前,我们的Playground.js组件只是在渲染一个计数器,可以在其中增加或减少计数。 现在,我们将对其进行更新,以便每次更改计数时,事物的颜色也将更改。

We use the

useState
Hook to set up the initial color, which we set to
null
and the function to update it (
setColor
). Now, we set up
useEffect
to update this color.
useEffect
's first argument is setColor, which we want to set to a
randomColor
.

我们使用

useState
Hook设置初始颜色(将其设置为
null
和用于对其进行更新的函数(
setColor
)。 现在,我们设置
useEffect
来更新该颜色。
useEffect
的第一个参数是setColor,我们要将其设置为
randomColor

As we only want a change in

count
to trigger
useEffect
, we set this as the second argument. If the count value hasn't changed, the Hook will not run the effect and the color will remain the same.

由于我们只希望更改

count
来触发
useEffect
,因此将其设置为第二个参数。 如果计数值未更改,则挂钩将不会运行效果,并且颜色将保持不变。

import React, { useState, useEffect } from "react";
import randomColor from "randomcolor";

export default function Playground() {
const [count, setCount] = useState(0);

const [color, setColor] = useState(null);
useEffect(() => {
setColor(randomColor());
}, [count]);

return (
<div style={{ borderTop: `10px solid ${color}` }}>
{count}
<button onClick={() => setCount((currentCount) => currentCount - 1)}>
-
</button>
<button onClick={() => setCount((currentCount) => currentCount + 1)}>
+
</button>
</div>
);
}

Now, our color changes every time we increment or decrement our count.

现在,每次增加或减少计数时,颜色都会改变。

useState
useEffect
挑战 (
useState
&
useEffect
Challenge)

It's now time to test the skills we have acquired so far. In this screencast, a function which gets some random colors for us has been added to <Paint.js />:

现在是时候测试我们到目前为止掌握的技能了。 在此截屏视频中,向我们提供了一些随机颜色的函数已添加到<Paint.js />:

const getColors = () => {
const baseColor = randomColor().slice(1);
fetch(`https://www.thecolorapi.com/scheme?hex=${baseColor}&mode=monochrome`)
.then((res) => res.json())
.then((res) => {
setColors(res.colors.map((color) => color.hex.value));
setActiveColor(res.colors[0].hex.value);
});
};

Our task is to write the functions for

setColors
, which will give us an array of hex colors and
setActiveColor
, which will tell use what the active color is.

我们的任务是为

setColors
编写函数,这将为我们提供十六进制颜色的数组,并为
setActiveColor
编写函数,这将告诉使用什么是活动颜色。

If we set up everything correctly, the UI will update with five colors which we can click on to expand. We only need

useState
and
useEffect
for this test.

如果我们正确设置了所有内容,则用户界面将更新为五种颜色,可以单击以展开。 我们仅需要

useState
useEffect
进行此测试。

useState
useEffect
解决方案# (
useState
&
useEffect
Solution#)

In this screencast, Christian walks us through how to give functionality to the

<ColorPicker />
component. At the end of it, we now have some colors:

截屏视频中,克里斯汀(Christian)指导我们如何为

<ColorPicker />
组件赋予功能。 最后,我们有了一些颜色:

useEffect
清理 (
useEffect
Clean Up)

Now we add a component called

<WindowSize.js />
which will show the window width and height at the bottom of the screen when the user resizes the window. This then disappears after half a second.

现在,我们添加了一个名为

<WindowSize.js />
的组件,当用户调整窗口大小时,它将在屏幕底部显示窗口的宽度和高度。 然后半秒钟后消失。

When we set up a timer or an event listener, we also need to clean it up once the component unmounts. This requires two pieces of state - the window size and visibility of the

<WindowSize />
component:

设置计时器或事件侦听器时,一旦组件卸载,我们还需要对其进行清理。 这需要两种状态-窗口大小和

<WindowSize />
组件的可见性:

export default function WindowSize() {
const [[windowWidth, windowHeight], setWindowSize] = useState([
window.innerWidth,
window.innerHeight,
]);
const [visible, setVisible] = useState(false);
}

Now we set up our effect, which adds the event listener:

现在我们设置效果,添加事件侦听器:

useEffect(() => {
const handleResize = () => {};
window.addEventListener("resize", handleResize);
});

Next, we set up the cleanup phase. This returns the function and an empty array is passed in to tell it that

useEffect
should only run on the first mount. The cleanup will then run and remove the event listener:

接下来,我们设置清理阶段。 这将返回该函数,并传入一个空数组以告诉它

useEffect
应该仅在第一次安装时运行。 然后将运行清理并删除事件侦听器:

useEffect(() => {
const handleResize = () => {};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);

We now set up the window size, the visibility and the timer so that the the resize window appears and then disappears after 500 milliseconds:

现在,我们设置窗口大小,可见性和计时器,以使调整大小窗口出现,然后在500毫秒后消失:

const [visible, setVisible] = useState(false);
useEffect(() => {
const handleResize = () => {
setWindowSize([window.innerWidth, window.innerHeight]);
setVisible(true);
setTimeout(() => setVisible(false), 500);
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);

However, we do not want to add a new timer every time the user resizes the window, so we also need to clean up the timer with

clearTimeout(timeoutId)
:

但是,我们不想每次用户调整窗口大小时都添加一个新计时器,因此我们还需要使用

clearTimeout(timeoutId)
清除计时器:

timeoutId = setTimeout(() => setVisible(false), 500);

To give

clearTimeout
the
timeoutId
from the last time the function ran, we use closures, which means that we declare our
timeoutId
variable outside the
handleResize
function. This way, the variable is still available to the inner function. Every time the function runs, the previous timeout will be cleared and a new one will be set up.

为了给

clearTimeout
从上一次运行该函数起提供
timeoutId
,我们使用了Closures ,这意味着我们在
handleResize
函数之外声明了
timeoutId
变量。 这样,变量仍可用于内部函数。 每次运行该功能时,上一个超时将被清除,并且将设置一个新的超时。

Lastly, we render our resize function to the browser.The final code can be seen in the screencast.

最后,我们将调整大小功能呈现给浏览器,最终的代码可以在截屏中看到。

Now, whenever the user resizes their window, the window size is set to the current window size, the visibility is set to true, and a timer is started to set the visibility to false after 500 milliseconds.

现在,每当用户调整窗口大小时,窗口大小将设置为当前窗口大小,可见性设置为true,并启动计时器以在500毫秒后将可见性设置为false。

useRef
挑战 (
useRef
Challenge)

If you need to access to actual DOM elements in React, you may need to use Refs. React has a Hook,

useRef
, which is dedicated to Refs.

如果您需要访问React中的实际DOM元素,则可能需要使用Refs。 React有一个Hook,

useRef
,专门用于Refs。

To use a Ref, it needs to be added to the element:

要使用Ref,需要将其添加到元素中:

<input
ref={inputRef}
type="range"
onChange={(e) => setCount(e.target.value)}
value={count}
/>

This input is a slider which updates the

count
and therefore the selected color. As the value is also tied to the count, the slider will also adjust if the count is changed via the buttons we added earlier.

此输入是一个滑块,可更新

count
并因此更新所选颜色。 由于该值也与计数相关,如果通过前面添加的按钮更改了计数,则滑块也会进行调整。

We have now declared our Ref, but we also need to set it up by calling

useRef
:

现在我们已经声明了Ref,但是我们还需要通过调用

useRef
来进行设置:

const inputRef = useRef();

In order to focus the input every time we change the count with the buttons, we simply add the necessary logic inside the effect which runs when the buttons are clicked:

为了每次使用按钮更改计数时都集中输入,我们只需在单击按钮时运行的效果内添加必要的逻辑即可:

useEffect(() => {
setColor(randomColor())
inputRef.current.focus()
},

Currently, the canvas is set to the height of the window itself, which makes it possible for the user to scroll within the canvas, which can lead to empty whitespace if the image is exported.

当前,画布设置为窗口本身的高度,这使用户可以在画布内滚动,如果导出图像,则可能导致空白。

Our challenge now is to ensure that the canvas of our paint app is only as big as the window minus the header height. To do this, we need to use useRef to get the height of the header and subtract it from the window's height.

现在我们面临的挑战是确保绘画应用程序的画布仅与窗口减去标题高度一样大。 为此,我们需要使用useRef来获取标题的高度,并将其从窗口的高度中减去。

useRef
解决方案 (
useRef
Solution)

In this screencast Christian walks us through how to get the correct canvas height with

useRef
.

截屏视频中,Christian引导我们了解如何使用

useRef
获得正确的画布高度。

After this, the user is no longer able to scroll, except for a few pixels offset between Scrimba's browser and a regular browser. There is now no whitespace at the bottom of the image.

此后,除了Scrimba浏览器和常规浏览器之间的几个像素偏移之外,用户不再能够滚动。 现在,图像底部没有空格。

useCallback
useMemo
+挑战 (
useCallback
&
useMemo
+ Challenge)

In this screencast, we are introduced to the concept of _ memoization_. This is when a pure function returns the same output from a calculation it has previous processed, rather than re-running the entire calculation:

在此截屏视频中,我们介绍了_ memoization_的概念。 这是当纯函数从先前处理过的计算返回相同的输出时,而不是重新运行整个计算时:

function Calculate(num) {
// first call, num === 3... ok I will calculate that
return fetchComplicatedAlgorithmToAdd47(3); // returns 50 after a while

// second call, num === 5... ok I guess I have to calculate that too
return fetchComplicatedAlgorithmToAdd47(5); // returns 52 after a while

// third call, num === 3... WAIT, I've seen this before! I know this one!
return 50; // immediately
}

React provides two Hooks which allow us to use memoization:

useCallback
and
useMemo
.

React提供了两个Hook,它们允许我们使用

useCallback
useCallback
useMemo

useCallback
### (
useCallback
###)

We start off with a very simple component in Playground.js which renders the number of times the function has rendered:

我们从Playground.js中的一个非常简单的组件开始,该组件呈现该函数呈现的次数:

function Calculate(num) {
const renderCount = useRef(1);
return <div>{renderCount.current++}</div>;
}

Now let's say that the component should only render when the count changes, but not when the color changes. To achieve this, we could use

useCallback
. We assign the result of
useCallback
to a variable called
calculate
:

现在让我们说,该组件仅在计数改变时才渲染,而在颜色改变时不应该渲染。 为此,我们可以使用

useCallback
。 我们的结果分配
useCallback
给一个变量称为
calculate

const calculate = useCallback(<Calculate />, [count]);

We will now render our new

calculate
variable instead of the
<Calculate />
component. Now, the component only renders when the count is changed, and not when the 'Change Color' button is clicked.

现在,我们将呈现新的

calculate
变量,而不是
<Calculate />
组件。 现在,该组件仅在更改计数时才渲染,而不是在单击“更改颜色”按钮时才渲染。

We also need to render our

<Calculate />
component instead of the variable we previously used and create a callback function. We use
useCallback
and assign it to a variable called
cb
. The
count
is the only dependency, meaning that if the count changes we will get a new function instance:

我们还需要呈现我们的

<Calculate />
组件而不是先前使用的变量,并创建一个回调函数。 我们使用
useCallback
并将其分配给名为
cb
的变量。
count
是唯一的依赖项,这意味着如果计数发生变化,我们将获得一个新的函数实例:

const cb = useCallback((num) => console.log(num), [count]);

Now we pass in a number (which is set to the count) to the

Calculate
component and the callback function, which we log to the console. Whenever the
Calculate
component re-renders (i.e. when the plus and minus buttons are clicked), the current count will be logged to the console.

现在,我们将一个数字(设置为count)传递给

Calculate
组件和回调函数,并将其登录到控制台。 每当重新
Calculate
组件时(即单击加号和减号按钮时),当前计数都将记录到控制台。

However, with this method, the count is also logged to the console when we click the 'Change Color' button. This is because we are using memoization for our

console.log
function, but not for our actual component, meaning that is not checking whether the callback function is the same as a previous one.

但是,使用这种方法,当我们单击“更改颜色”按钮时,计数也会记录到控制台。 这是因为我们正在为

console.log
函数使用备忘录,但没有为实际组件使用备忘录,这意味着不检查回调函数是否与上一个相同。

React.memo
(
React.memo
)

To solve this, we add React.memo to the

Calculate
component. Now, it will check the inputs and see whether they are the same, and will not render if so:

为了解决这个问题,我们将React.memo添加到

Calculate
组件中。 现在,它将检查输入并查看它们是否相同,如果相同,将不进行渲染:

const Calculate = React.memo(({ cb, num }) => {
cb(num);
const renderCount = useRef(1);
return <div>{renderCount.current++}</div>;
});

The 'Change Color' button now no longer logs the count to the console.

现在,“更改颜色”按钮不再将计数记录到控制台。

useMemo
### (
useMemo
###)

To see what

useMemo
can do, we add a
useCallback
call right next to a
useMemo
call:

要查看

useMemo
可以做什么,我们在
useCallback
调用旁边添加一个
useMemo
调用:

useCallback(() => console.log("useCallback"));
useMemo(() => console.log("useMemo"));

This tells us that

useMemo
is used every time the function renders. This is because
useCallback
returns the functions, whereas
useMemo
returns the result of the function:

这告诉我们每次函数渲染时都会使用

useMemo
。 这是因为
useCallback
返回函数,而
useMemo
返回函数结果:

useCallback(() => console.log("useCallback")); // return the function
useMemo(() => console.log("useMemo")); // return the result of the function

useMemo
can be used for some expensive functions which you want to memoize.
UseCallback
, on the other hand, is better for passing a callback into a component when you don't want to render the component unnecessarily.

useMemo
可用于一些您想
useMemo
昂贵功能。 另一方面,
UseCallback
可以在您不想不必要地呈现组件时将回调传递给组件。

The screencast finishes with a new challenge. Our paint app currently offers only a few colors to work with. Our challenge is to add some functionality to a newly-added refresh button so that the user can click the button and get some new colors. This should take place in

RefreshButton.js
, which is currently taking in a callback and should be calling that callback when the refresh button is clicked. Our challenge is to pass in the callback using
useCallback
or
useMemo
.

截屏视频结束了新的挑战。 我们的绘画应用程序目前仅提供几种颜色供您使用。 我们的挑战是为新添加的刷新按钮添加一些功能,以便用户单击该按钮并获得一些新的颜色。 这应该在

RefreshButton.js
,该当前正在接受回调,并且在单击刷新按钮时应调用该回调。 我们的挑战是使用
useCallback
useMemo
传递回调。

As a bonus challenge, we are also asked to use

React.memo
to memoize the
<Name />
component, which is currently rendering unnecessarily every time we change our colors.

作为一个额外的挑战,我们还被要求使用

React.memo
<Name />
组件,该组件当前每次更改颜色时都不必要地渲染。

useCallback
解决方案 (
useCallback
Solution)

Now, Christian walks us through the solution to the previous challenges, follow him in this marvellous screencast.

现在,克里斯汀(Christian)带领我们完成了先前挑战的解决方案,并在这个出色的截屏视频中跟随他。

At the end of the screencast, our refresh button is now supplying shiny new colors when clicked:

在截屏视频的结尾,单击时,我们的刷新按钮现在将提供闪亮的新颜色:

定制钩 (Custom Hooks)

Here, we learn about custom Hooks by refactoring the

<WindowSize />
component into a Hook. This is great for reusability.

在这里,我们通过将

<WindowSize />
组件重构为挂钩来了解自定义挂钩。 这对于可重用性非常有用。

Currently,

<WindowSize />
is handling two different sets of state; the window size and visibility. As visibility might not be needed in future uses of
<WindowSize />
, we move its logic into our
<Paint />
component, which is also where we will use our
useWindowSize
Hook.

当前,

<WindowSize />
正在处理两个不同的状态集。 窗口大小和可见性。 由于将来使用
<WindowSize />
可能不需要可见性,因此我们将其逻辑移到
<Paint />
组件中,这也是我们将使用
useWindowSize
Hook的地方。

The following lines are removed from

WindowSize.js
:

以下行已从

WindowSize.js
中删除:

let timeoutId;
///
setVisible(true);
clearTimeout(timeoutId);
timeoutId = setTimeout(() => setVisible(false), 500);

Additionally, the following lines now need to be returned from

<Paint.js />
instead of
<WindowSize />
:

此外,现在需要从

<Paint.js />
而不是
<WindowSize />
返回以下行:

<div className={`window-size ${visible ? "" : "hidden"}`}>
{windowWidth} x {windowHeight}
</div>

The window width and height will be returned from

<WindowSize />
:

窗口的宽度和高度将从

<WindowSize />
返回:

return [windowWidth, windowHeight];

To make the

windowWidth
and
windowHeight
variables available, we add the following code to
<Paint.js />
:

为了使

windowWidth
windowHeight
变量可用,我们将以下代码添加到
<Paint.js />

const [windowWidth, windowHeight] = useWindowSize();

To implement the visibility logic so that we can show and hide the window size as necessary, we pass in a callback to our

useWindowSize
Hook and use a Ref to make
timeoutID
available between renders:

为了实现可见性逻辑,以便我们可以根据需要显示和隐藏窗口大小,我们将回调传递给

useWindowSize
Hook,并使用Ref使
timeoutID
在渲染之间可用:

let timeoutId = useRef();
const [windowWidth, windowHeight] = useWindowSize(() => {
setVisible(true);
clearTimeout(timeoutId.current);
timeoutId.current = setTimeout(() => setVisible(false), 500);
});

We can now call this when we need to from

<WindowSize />
:

现在,我们可以在

<WindowSize />
调用它:

export default function useWindowSize(cb) {
const [[windowWidth, windowHeight], setWindowSize] = useState([
window.innerWidth,
window.innerHeight,
]);

useEffect(() => {
const handleResize = () => {
cb();
setWindowSize([window.innerWidth, window.innerHeight]);
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return [windowWidth, windowHeight];
}

We now have the same functionality as before but the

<WindowSize />
logic is in a reusable Hook.

现在,我们具有与以前相同的功能,但是

<WindowSize />
逻辑位于可重用的Hook中。

The lessons ends with another challenge - to convert the

<Canvas />
component into a function which uses Hooks instead of lifecycle methods.

这些课程以另一个挑战结束-将

<Canvas />
组件转换为使用Hooks而非生命周期方法的函数。

使用Hooks构建绘画应用 (Building the paint app with Hooks)

This screencast walks us through how to convert

<Canvas />
into a functional component using Hooks. It also shows us how to refactor our app to make it much cleaner and more readable. A big advantage of using Hooks is that all related logic is next to each other, in contrast to our old components in which related logic items were separated from each other.

该截屏视频指导我们如何使用Hooks将

<Canvas />
转换为功能组件。 它还向我们展示了如何重构我们的应用程序,使其更加整洁和可读性强。 使用Hooks的一大优势是,所有相关的逻辑都彼此相邻,这与我们以前的旧组件不同,在旧的组件中,相关的逻辑项彼此分开。

At the end of the screencast, our paint app is finally finished and we are ready to paint our masterpieces:

在截屏视频的结尾,我们的绘画应用程序终于完成了,我们可以绘画我们的杰作了:

奥托罗 (Outro)

We have now finished the React Hooks course. We have learnt about:

现在,我们已经完成了React Hooks课程。 我们了解到:

  • useState
    , which manages state

    useState
    ,它管理状态

  • useEffect
    , which does side effects,

    useEffect
    ,它有副作用,

  • useRef
    , which gets references to DOM elements and keeps values across renders

    useRef
    ,它获取对DOM元素的引用并在渲染器之间保留值

  • useCallback
    , which creates functions which don't need to be created on every render

    useCallback
    ,它创建不需要在每个渲染器上都创建的函数

  • useMemo
    , which memoizes expensive computations

    useMemo
    ,用于记忆昂贵的计算

  • React.Memo
    , which can go around a React component and memoize it

    React.Memo
    ,它可以绕过React组件并对其进行
    React.Memo

  • custom Hooks
    , which allow us to create our own reusable logic.

    custom Hooks
    ,它允许我们创建自己的可重用逻辑。

There are two rules to keep in mind when using any of these Hooks:

使用这些挂钩中的任何两个时,都需要牢记两个规则:

  1. Only call Hooks at the top level of the React component, i.e. not within if blocks or anything similar.

    仅在React组件的顶层调用Hook,即不在if块或类似内容之内。
  2. Only call Hooks from React functions, not your own custom functions.

    仅从React函数调用Hook,而不是您自己的自定义函数。

Congratulations on following the tutorial and learning all the skills used in this project. To further your learning, check out Scrimba's free, six-hour Learn React for Free course which aims to make you a React wizard!

恭喜您按照教程学习了本项目中使用的所有技能。 为了进一步学习,请查看Scrimba的免费六小时免费学习React免费课程,该课程旨在使您成为React向导!

Happy coding!

编码愉快!

翻译自: https://www.freecodecamp.org/news/learn-react-hooks-by-building-a-paint-app/

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐