React 中的 useEffect:你需要知道的一切
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
只需理解这一点:我们使用 useEffect 在视图渲染完成后执行某些操作。
现在,让我们开始编写代码,创建一个简单的计数器来理解 useEffect:
import {useState, useEffect} from 'react'
export default function App() {
const [counter, setCounter] = useState(0)
useEffect(() => {
console.log('from useEffect...', counter)
})
function incrementClickHandler() {
setCounter(counter+1)
console.log("Inside incrementClickHandler.....", counter)
}
console.log('before render...', counter)
return (
<div className='App'>
<h1>{counter} </h1>
<button onClick={incrementClickHandler}>Increment</button>
</div>
)
}
以下是初始渲染后的控制台输出结果(即尚未点击递增按钮): 代码或函数写在哪里并不重要,流程如下👇:
返回值中的 HTML将会首次渲染。然而,在渲染完成之前console.log('before render...', counter)
,useEffect 内部的函数会立即执行,视图渲染完成后才会执行。(由于我们还没有点击递增按钮,因此 incrementClickHandler 函数不会执行。)
下图👇是点击递增按钮后的流程图:
步骤 1:在执行 HTML 部分时,我们会遇到 onClick 事件,因此会调用 incrementClickHandler 函数。
步骤 2:请注意,`incrementClickHandler` 函数内部存在状态更新。然而,状态更新后的 `console.log` 输出的是之前的状态。这是因为,当函数内部更新状态时,实际的状态更新只能在函数外部生效,退出 `incrementClickHandler` 函数后,整个应用程序会使用新的状态重新运行。
步骤 3:虽然整个应用程序再次运行,但 useEffect 和更新状态的函数将不会执行。
步骤 4:由于整个应用程序正在运行,console.log('before render...', counter)
因此将执行。
步骤 5:现在,视图将被渲染,递增按钮上方的数字将从 0 变为 1。
步骤 6. 现在视图已经渲染完成,useEffect 将运行。
我解释了以上所有代码,是为了让您明白 useEffect 是在视图渲染完成后运行的。
你可能会问:为什么要在视图渲染之后才调用 useState 函数?
原因如下:因为用户只关心视图,他们并不关心你的 console.log 或 localStorage(或者任何其他副作用)。因此,你应该在后端最后修改状态,并且视图应该立即反映出这个状态。如果在状态修改和视图渲染之间有任何延迟,那么这个延迟总是会拖慢渲染速度,降低用户体验。
现在你已经对 useEffect hook 有了基本的了解,让我们来了解一下它的依赖项。
依赖数组
依赖项数组是 useEffect 函数的第二个可选参数。
顾名思义,它是一个依赖项数组,当数组中的依赖项发生变化时,useEffect 函数内部的相应函数就会运行。
请参见下图:
让我们通过以下示例来理解上表:
import "./styles.css";
import { useEffect, useState } from 'react'
export default function App() {
const [resource, setResource] = useState('');
const [input, setInput] = useState('');
useEffect(() => {console.log('See The Magic')})
return (
<div className="App">
<h3>Input Element</h3>
<input onChange={e => setInput(e.target.value)}></input>
<h3>Buttons</h3>
<button onClick={() => setResource('Users')}>Users</button>
<button onClick={() => setResource('Posts')}>Posts</button>
<button onClick={() => setResource('Comments')}>Comments</button>
</div>
);
}
依赖项数组中只传递状态变量,useEffect 内部的函数仅在数组中提供的状态发生变化时才会运行。
我们将使用上面的示例来理解上表中给出的所有依赖项(数组值)。
情况 1:数组值:未传递值
这是默认情况,因此 useEffect 内部的函数会在每次渲染或每次状态更改后运行。
useEffect(() => {console.log('See The Magic')})
情况 2:数组值:传递了空数组
我在定义中已经提到,依赖数组是第二个可选参数。因此,在这种情况下,我们将在 useEffect 中添加一个空数组 ([]),其他部分保持不变。
useEffect(() => {console.log('See The Magic')}, [])
由于我们的数组为空,并且没有传递任何状态,因此 useEffect 内部的函数只会运行一次(在初始渲染时)。
情况 3:数组值:[状态变量 1]
我在定义中提到过,依赖数组是第二个可选参数。因此,在这个例子中,我们将在 useEffect 中添加一个包含单个状态变量的数组,看看会发生什么。
useEffect(() => {console.log('See The Magic')}, [resource])
由于我们在数组中传递了资源值,因此 useEffect 内部的函数只会在资源值发生变化时运行。 请注意,即使状态发生了变化,当我们在输入框中输入内容时,useEffect 内部的函数也不会运行。这是因为我们只在依赖数组中传递了资源状态。
数组值:[状态变量 2]
现在,我们不用资源状态,而是传递输入状态,看看会发生什么。
useEffect(() => {console.log('See The Magic')}, [input])
正如预期,当我们点击按钮时,useEffect 函数内部的函数不会运行。但是,当我们在输入框中输入内容时,它会运行。
由于我们在依赖数组中传递了输入状态,因此 useEffect 函数仅依赖于输入状态。
### 案例 4:数组值:[stateVariable1, stateVariable2]
在这种情况下,我们将把两个状态变量([resource, input])都传递给 useEffect,看看会发生什么。
useEffect(() => {console.log('See The Magic')}, [resource, input])
如上所示,当提供的两个状态中的任何一个发生变化时,useEffect 都会做出响应。但是,您可能会注意到它的行为与第一个条件(即未传递依赖数组)完全相同。这是因为我们只有两个状态,并且已将它们都传递到了依赖数组中。如果状态超过两个,情况可能就不同了。
还有一点需要注意的是,依赖数组中只传递状态变量(没有普通变量)。
好了,各位,希望你们理解了 useEffect。
如果您有任何疑问,请在评论区留言,我会尽快回复。
我写一篇与Web开发(主要是React)相关的文章。
如果你喜欢这篇文章,请在推特上关注我: @therajatg
如果您也使用领英,欢迎联系我:https://www.linkedin.com/in/therajatg/
祝你今天过得愉快😀!
原文发布于https://rajatgupta.net/useeffect-in-react-everything-you-need-to-know
文章来源:https://dev.to/therajatg/useeffect-in-react-everything-you-need-to-know-512k


