发布于 2026-01-06 10 阅读
0

UseEffect 依赖数组和对象比较!DEV 全球展示挑战赛,由 Mux 呈现:展示你的项目!

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])
}

Enter fullscreen mode Exit fullscreen mode

这样,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]);
}
Enter fullscreen mode Exit fullscreen mode

正如代码所示,我们创建了同一个对象的另一个副本。虽然这似乎解决了问题,但这种方法也存在问题。我们都知道,在 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]);
}
Enter fullscreen mode Exit fullscreen mode

与上述函数类似,createUser 函数仅在用户名、电子邮件和地址发生更改并创建新的User对象时才会被调用。这样可以确保比较依赖数组中对象的正确副本,并优化不必要的重新渲染。

这是使用 useEffect 时比较棘手的问题之一,因为我们常常忽略 React 会比较对象的引用。直接将对象传递给 useEffect 会导致函数出现 bug,最终我们会花费大量时间去找出问题所在!(我经常遇到这种情况!)

本文到此结束,希望对您有所帮助!请问您是如何解决将对象传递给依赖数组的问题的?当然,也欢迎您对本文提出任何想法、评论或反馈 :)

你也可以在推特上关注我,或者如果你喜欢我的文章,可以请我喝杯咖啡

继续学习🙌

文章来源:https://dev.to/hey_yogini/useeffect-dependency-array-and-object-comparison-45el