UseEffect 依赖数组和对象比较!
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
大家好!
如果你的函数中存在任何副作用,那么必须使用 ` useEffect`钩子。`useEffect` 钩子接受两个参数:第一个参数是一个用于执行副作用的函数,第二个参数是一个依赖项数组。如果你不想在每次渲染时都执行副作用(这种情况几乎总是如此),则需要向这个依赖项数组传递一些值,或者至少传递一个空数组。如果数组中的值发生变化,`useEffect` 将会重新运行。当依赖项数组中传递的值是布尔值、字符串或数字类型时,这种方法可以完美运行。但是,当处理对象或数组等复杂类型时,就会出现一些问题。
在深入探讨问题的解决方案之前,让我们先详细了解一下这个问题。
React 总是使用引用来比较对象和数组。在以下两种情况下,useEffect 的执行可能会受到影响:
1. 对象或数组完全相同,但使用了不同的引用进行比较;
2. 对象或数组的值不同,但使用了相同的引用进行比较。
在这两种情况下,useEffect hook 都无法正确执行,从而导致应用程序中出现错误。
这个问题可能有两种解决方法。让我们详细了解一下——
创建对详细信息的依赖关系
假设有一个对象,其中包含所有用户详细信息,并作为 prop 传递给函数。在你的应用中,你希望仅在用户名更改时才执行副作用。那么,在这种情况下,依赖关系就非常明确了!不要将整个用户详细信息对象传递给 useEffect,而只需传递相关的详细信息即可。例如:
function UserProfile({userDetails}) {
const [error, setError] = useState(‘’);
useEffect(() => {
if(userDetails.username) {
// Do something…!
}
}, [userDetails.username])
}
这样,useEffect 会比较确切的值,并且仅在用户名更改时重新运行。这种方法适用于依赖项数量较少的情况,但如果数组变大,则代码不够简洁且可扩展。
记忆对象
解决这个问题还有另一种方法,那就是每次都创建一个新对象。这样,我们就能确保所有更改都被记录下来,并且不会对同一个对象的引用进行比较。为了更好地理解,我们来看代码——
function UserProfile({ userDetails }) {
const [error, setError] = useState('');
const [user, setUser] = useState({
username: userDetails.username,
email: userDetails.email,
address: userDetails.address,
});
useEffect(() => {
if (userDetails.username) {
// Do something…!
}
}, [userDetails.username]);
}
正如代码所示,我们创建了同一个对象的另一个副本。虽然这似乎解决了问题,但这种方法也存在问题。我们都知道,在 JavaScript 中创建对象是一项开销很大的操作,而我们却试图执行两次!除此之外,我们还重复编写了代码,这同样不是一个好的做法。
为了解决所有这些问题,对象记忆化就成了一种非常简单且易于维护的解决方案。让我们来看看它是如何实现的——
对象记忆化意味着我们尝试保存对象的记忆。更准确地说,我们缓存对象并在函数中维护其唯一副本。当函数重新渲染时,函数会使用同一个副本,直到该对象的任何属性不再发生变化。这样,我们既可以最大限度地减少创建对象的开销,又能确保能够及时捕获属性变化。
为了实现记忆化功能,我们使用了React 的useMemo hook。让我们来看一下代码——
function UserProfile({ userDetails }) {
const [error, setError] = useState('');
const { username, email, address } = userDetails;
const user = useMemo(() => createUser({ username, email, address }), [
username,
email,
address,
]);
useEffect(() => {
if (username) {
// Do something…!
}
}, [user]);
}
与上述函数类似,createUser 函数仅在用户名、电子邮件和地址发生更改并创建新的User对象时才会被调用。这样可以确保比较依赖数组中对象的正确副本,并优化不必要的重新渲染。
这是使用 useEffect 时比较棘手的问题之一,因为我们常常忽略 React 会比较对象的引用。直接将对象传递给 useEffect 会导致函数出现 bug,最终我们会花费大量时间去找出问题所在!(我经常遇到这种情况!)
本文到此结束,希望对您有所帮助!请问您是如何解决将对象传递给依赖数组的问题的?当然,也欢迎您对本文提出任何想法、评论或反馈 :)
你也可以在推特上关注我,或者如果你喜欢我的文章,可以请我喝杯咖啡。
继续学习🙌
文章来源:https://dev.to/hey_yogini/useeffect-dependency-array-and-object-comparison-45el