React useEffect 清理:如何以及何时使用它

2025-05-26

React useEffect 清理:如何以及何时使用它

代码片段

您是否遇到过以下错误?


Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

Enter fullscreen mode Exit fullscreen mode

消息很简单。我们正在尝试更改组件的状态,即使它已被卸载且不可用。

发生这种情况的原因有很多,但最常见的是我们没有取消订阅 websocket 组件,或者在异步操作完成之前卸载了它。

我们怎样才能解决这个问题?

useEffect 钩子中的清理函数。

useEffect hook 的构建方式是,如果我们在方法中返回一个函数,则该函数将在组件解除关联时执行。这非常有用,因为我们可以用它来消除不必要的行为或防止内存泄漏问题。

因此,如果我们想要清理订阅,代码将如下所示:

useEffect(() => {
    API.subscribe()
    return function cleanup() {
        API.unsubscribe()
    }
})
Enter fullscreen mode Exit fullscreen mode

不要更新未挂载组件的状态

一种常见的实现是在异步函数完成后更新组件状态。但是,如果组件在完成后卸载了会发生什么?如果我们无法控制,它无论如何都会尝试设置状态。

在实际场景中,我在 React Native 上遇到过这样的情况,用户可以在进程结束之前离开屏幕。

在下面的例子中,我们有一个异步函数执行一些操作,当它运行时,我希望渲染一条“正在加载”的消息。函数执行完成后,我将状态从“正在加载”改为“正在加载”,并渲染另一条消息。

function Example(props) {
    const [loading, setloading] = useState(true)

    useEffect(() => {
        fetchAPI.then(() => {
            setloading(false)
        })
    }, [])

    return <div>{loading ? <p>loading...</p> : <p>Fetched!!</p>}</div>
}
Enter fullscreen mode Exit fullscreen mode

但是,如果我们退出组件,fetchAPI 结束并设置加载状态,就会出现开头提到的错误。所以我们需要确保 fetchAPI 完成时组件仍然处于挂载状态。

function Example(props) {
    const [loading, setloading] = useState(true)

    useEffect(() => {
        let mounted = true
        fetchAPI.then(() => {
            if (mounted) {
                setloading(false)
            }
        })

        return function cleanup() {
            mounted = false
        }
    }, [])

    return <div>{loading ? <p>loading...</p> : <p>Fetched!!</p>}</div>
}
Enter fullscreen mode Exit fullscreen mode

这样我们就可以判断组件是否仍然挂载。只需添加一个变量,如果我们卸载该变量,该变量的值将变为 false。

额外:取消 Axios 请求

Axios 提供了取消选项,可以在请求结束前完成。除了清理功能外,此功能还有助于防止内存泄漏。

useEffect(() => {
    const source = axios.CancelToken.source()

    const fetchUsers = async () => {
        try {
            await Axios.get('/users', {
                cancelToken: source.token,
            })
            // ...
        } catch (error) {
            if (Axios.isCancel(error)) {
            } else {
                throw error
            }
        }
    }

    fetchData()

    return () => {
        source.cancel()
    }
}, [])
Enter fullscreen mode Exit fullscreen mode

结论

useEffect hook 中的清理函数还有很多其他用法,但我希望本文能帮助您更好地了解如何以及何时使用它。
欢迎您提出任何评论或建议,我将不胜感激。 

文章来源:https://dev.to/otamnitram/react-useeffect-cleanup-how-and-when-to-use-it-2hbm
PREV
在 React 中正确排序导入
NEXT
freeCodeCamp.org 如何使用 JAMstack + 单个 API 服务器帮助每月数百万人学习编码