paint-brush
React 的 UseEffect Hook 中的清除函数——解释经过@ljaviertovar
50,767 讀數
50,767 讀數

React 的 UseEffect Hook 中的清除函数——解释

经过 L Javier Tovar6m2022/12/01
Read on Terminal Reader
Read this story w/o Javascript

太長; 讀書

如果您开始学习 React 或已经有一段时间使用这个库,那么您肯定会遇到一些与异步函数相关的错误或警告,尤其是使用 hook useEffect 时。 当我学习这个钩子的功能时,我无法理解为什么要在这个函数中使用 return,因为在大多数情况下没有必要使用它,没有它 React 也能很好地工作。

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - React 的 UseEffect Hook 中的清除函数——解释
L Javier Tovar HackerNoon profile picture

有例子。


如果您开始学习 React 或已经有时间使用这个库,那么您肯定会遇到一些与异步函数相关的错误或警告,尤其是使用 hook useEffect时。


当我在学习这个钩子的功能时,我无法理解为什么要在这个函数中使用 return ,因为在大多数情况下没有必要使用它,没有它 React 也能很好地工作。


随着越来越熟悉 React 的工作方式和组件的生命周期,我开始注意到,在很多情况下,在 hook useEffect中使用 return 太重要了,尤其是在副作用方面。


有什么副作用?

副作用可能是从远程服务器获取数据、读取或写入本地存储、设置事件侦听器或设置订阅。单击按钮、提交表单或安装和卸载组件时,可能会出现这些副作用。


React 的useEffect钩子允许功能组件在组件挂载或某些属性或状态发生变化时执行操作。此挂钩还允许在卸载组件时进行清理。


为什么要清除副作用?

在 React 中处理副作用是一项中等复杂度的任务。然而,有时,您可能会在组件生命周期(初始渲染、组装、使用、拆卸)和副作用生命周期(开始、进行中、完成)的交叉点遇到困难。


一个这样的困难是当副作用完成并尝试更新已拆卸组件的状态时。


这会导致像这样的 React 警告:


内存泄漏


React 应用程序中的内存泄漏主要是由于在卸载组件之前未取消挂载组件时进行的订阅而导致的。

它们会导致许多问题,包括:


  • 通过减少可用内存量来影响项目的性能。
  • 减慢应用程序。
  • 系统崩溃。


因此,有必要消除内存泄漏问题。


什么是useEffect清理函数?

它是useEffect挂钩的一个功能,它允许我们在卸载组件之前停止不再需要执行的副作用。


useEffect构建方式使我们可以在其中返回一个函数,而这个返回函数就是清理发生的地方。


例如,组件 A 请求 API 获取产品列表,但在发出该异步请求时,组件 A 从 DOM 中删除(已卸载)。不需要完成那个异步请求。


因此,作为改进应用程序的清理方法,您可以清理(取消)异步请求,使其未完成。

的清理功能useEffect


 useEffect(() => { // Your effect return () => { // Cleanup } }, [input])


清理效果

取消获取请求

有多种方法可以取消 fetch 请求调用,我们可以使用 fetch AbortController或 Axios AbortController.


要使用AbortController ,我们必须使用AbortController()构造函数创建一个控制器。然后,当我们的获取请求启动时,我们将AbortSignal作为请求的options对象中的选项传递。


这将控制器和信号与获取请求关联起来,让我们可以随时使用AbortController.abort()取消它:


 useEffect(() => { //create a controller let controller = new AbortController(); (async () => { try { const response = await fetch(API, { // connect the controller with the fetch request signal: controller.signal, }, ); // handle success setList(await response.json()); // remove the controller controller = null; } catch (e) { // Handle the error } })(); //aborts the request when the component umounts return () => controller?.abort(); },[]);


 useEffect(() => { // create a controller const controller = new AbortController(); axios .get(API, { signal: controller.signal }) .then({data}) => { // handle success setList(data); }) .catch((err) => { // Handle the error }); //aborts the request when the component umounts return () => controller?.abort(); }, []);


清理超时

当使用setTimeout(callback, time)定时器函数时,我们可以使用特殊的clearTimeout(timerId)函数在卸载时清除它们。


 useEffect(() => { let timerId = setTimeout(() => { // do something timerId = null; }, 3000); // cleanup the timmer when component unmout return () => clearTimeout(timerId); }, []);


清理间隔

与超时一样, setIntervals(callback, time)有一个特殊的功能,可以使用clearInterval(intervalId)函数清除它们。


 useEffect(() => { let intervalId = setInterval(() => { // do something like update the state }, 1000); // cleanup the timer when component unmout return () => clearInterval(interval); }, []);


清理事件监听器

通过window.removeEventListener清理监听器。 removeEventListener调用必须在removeEventListener调用中引用相同的函数才能正确删除侦听器。


 useEffect(() => { // function to add to EventListener const handleKeyUp= (event) => { switch (event.key) { case "Escape": setCollapsed(true); break; } } window.addEventListener("keyup", handleKeyUp); // cleanup the listener when component unmout return () => window.removeEventListener("keyup", handleKeyUp); }, []);


清理 Web 套接字

当你创建一个WebSocket连接,您可以在清理socket.close()函数中关闭它。


 useEffect(() => { const ws = new WebSocket(url, protocols) // do what you want with the socket ws.onmessage = (event) => { setValue(JSON.parse(event.data)); }; // cleanup the web socket when component unmout return () => ws.close() }, [])


结论

我们了解到,一些副作用需要清理以避免内存泄漏和不必要的和不需要的行为。我们必须学会何时以及如何使用useEffect钩子的清理功能来避免这些问题并优化应用程序。


我建议在卸载组件时清理异步效果。此外,如果异步副作用取决于 prop 或 state 值,那么也可以考虑在组件更新时清理它们。


我希望您觉得本文有用,并且您现在可以正确使用清理功能。


阅读更多:

也发布在这里