这似乎是一个奇怪的问题,但我并没有真正看到 React 中useEffect
的用例很多(我目前正在研究几千行 React 代码库,从未使用过一次(,我认为可能有一些我没有完全掌握的东西。
如果您正在编写功能组件,将"效果"代码放在useEffect
钩子中与简单地在功能组件的主体中执行它(也在每次渲染时执行(有什么区别?
一个典型的用例是在挂载组件时获取数据:我看到两种方法,一种是useEffect
,另一种是没有:
// without useEffect
const MyComponent = () => {
[data, setData] = useState();
if (!data) fetchDataFromAPI().then(res => setData(res));
return(
{data ? <div>{data}</div> : <div>Loading...</div>}
)
}
// with useEffect
const MyComponent = () => {
[data, setData] = useState();
useEffect(() => {
fetchDataFromAPI().then(res => setData(res))
}, []);
return(
{data ? <div>{data}</div> : <div>Loading...</div>}
)
}
在此类用例中useEffect
是否有优势(性能方面或其他方面(?
I. 清理
如果您的组件在获取完成之前被销毁怎么办?您收到错误。
useEffect
为您提供了一种清理处理程序返回值的简单方法。
二、对道具变化的反应。
如果你有一个userId
传入了你用来获取数据的道具怎么办。如果没有useEffect
,您必须在状态下复制userId
,以便能够判断它是否发生了变化,以便您可以获取新数据。
问题是,useEffect并不是在每个渲染上都执行的。
为了更清楚地看到这一点,让我们假设您的组件MyComponent
由父组件渲染(我们称之为ParentComponent
(,并且它从该父组件接收一个可以从用户操作更改的 prop。
父组件
const ParentComponent = () => {
const [ counter, setCounter ] = useState(0);
const onButtonClicked = () => setCounter(counter + 1);
return (
<>
<button onClick={onButtonClicked}>Click me!</button>
<MyComponent counter={counter} />
</>
);
}
还有你的MyComponent
(稍微修改一下以阅读和使用counter
道具(:
const MyComponent = ({ counter }) => {
[data, setData] = useState();
useEffect(() => {
fetchDataFromAPI().then(res => setData(res))
}, []);
return(
<div>
<div>{counter}</div>
{data ? <div>{data}</div> : <div>Loading...</div>}
</div>
)
}
现在,当组件MyComponent
首次挂载时,将执行获取操作。如果稍后用户单击按钮并且计数器增加,则不会执行useEffect(但由于counter
更改,将调用MyComponent
函数以进行更新(!
如果不使用useEffect,当用户点击按钮时,获取操作将再次执行,因为计数器 prop 已更改,并且执行了MyComponent
的渲染方法。
useEffect 正在处理问题的副作用。 useEffect 是componentDidMount 和 componentDidUpdate的组合。 每个初始渲染以及每当 props更新时都会执行它。
例如:
useEffect(() => {
fetchDataFromAPI().then(res => setData(res))
}, []);
再比如:
假设您有多个状态变量,组件将针对每个状态值更改重新呈现。但是我们可能需要在特定场景中运行 useEffect,而不是为每个状态更改执行它。
function SimpleUseEffect() {
let [userCount, setUserCount] = useState(0);
let [simpleCount, setSimpleCount] = useState(0);
useEffect(() => {
alert("Component User Count Updated...");
}, [userCount]);
useEffect(() => {
alert("Component Simple Count Updated");
}, [simpleCount]);
return (
<div>
<b>User Count: {userCount}</b>
<b>Simple Count: {simpleCount}</b>
<input type="button" onClick={() => setUserCount(userCount + 1}} value="Add Employee" />
<input type="button" onClick={() => setSimpleCount(simpleCount + 1}} value="Update Simple Count" />
</div>
)
}
在上面的代码中,每当你的 props 请求发生变化时,fetchDataFromAPI 都会执行并更新响应数据。如果不使用 useEffect,则需要自动处理所有类型的副作用。
对数据进行异步 API 调用
设置对可观察量的订阅
手动更新 DOM 元素
从函数内部更新全局变量
有关更多详细信息,请参阅此博客 https://medium.com/better-programming/https-medium-com-mayank-gupta-6-88-react-useeffect-hooks-in-action-2da971cfe83f