Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/396.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 清除React钩子中未安装组件上的内存泄漏_Javascript_Reactjs_Promise_React Hooks_Inertiajs - Fatal编程技术网

Javascript 清除React钩子中未安装组件上的内存泄漏

Javascript 清除React钩子中未安装组件上的内存泄漏,javascript,reactjs,promise,react-hooks,inertiajs,Javascript,Reactjs,Promise,React Hooks,Inertiajs,我是使用React的新手,所以这可能很容易实现,但即使我做了一些研究,我自己也无法解决。如果这太愚蠢,请原谅我 上下文 我正在使用Laravel(后端)和React(前端)适配器。如果你不知道惯性,它基本上是: Inertia.js允许您快速构建现代的单页React、Vue和 使用经典服务器端路由和控制器的苗条应用程序 问题 我正在做一个简单的登录页面,它有一个表单,提交后将执行POST请求以加载下一个页面。它似乎工作正常,但在其他页面中,控制台显示以下警告: 警告:无法对已卸载的组件执行Rea

我是使用React的新手,所以这可能很容易实现,但即使我做了一些研究,我自己也无法解决。如果这太愚蠢,请原谅我

上下文 我正在使用Laravel(后端)和React(前端)适配器。如果你不知道惯性,它基本上是:

Inertia.js允许您快速构建现代的单页React、Vue和 使用经典服务器端路由和控制器的苗条应用程序

问题 我正在做一个简单的登录页面,它有一个表单,提交后将执行POST请求以加载下一个页面。它似乎工作正常,但在其他页面中,控制台显示以下警告:

警告:无法对已卸载的组件执行React状态更新。 这是一个no-op,但它表示应用程序中存在内存泄漏。 若要修复,请取消useEffect中的所有订阅和异步任务 清理功能

登录中(由惯性创建)

相关代码(为了避免不相关的行,我对其进行了简化):


您可以使用惯性的“取消活动访问”方法来取消
useffect
清理挂钩中的活动
visit

因此,通过此呼叫,活动的
访问将被取消,状态将不会更新

useEffect(() => {
    return () => {
        Inertia.cancelActiveVisits(); //To cancel the active visit.
    }
}, []);

如果
惯性
请求被取消,那么它将返回一个空响应,因此您必须添加额外的检查来处理空响应。 同时添加catch块以处理任何潜在错误

 function handleSubmit(e) {
    e.preventDefault();
    setLoading(true);
    Inertia.post(window.route('login.attempt'), values)
      .then(data => {
         if(data) {
            setLoading(false);
         }
      })
      .catch( error => {
         console.log(error);
      });
  }
替代方法(解决方法)

您可以使用
useRef
保存组件的状态,并在此基础上更新
状态

问题:

let _componentStatus.current =  useRef(true);
useEffect(() => {
    return () => {
        _componentStatus.current = false;
    }
}, []);
之所以显示该状态,是因为
handleSubmit
正在尝试更新组件的状态,即使组件已从dom中卸载

解决方案:

let _componentStatus.current =  useRef(true);
useEffect(() => {
    return () => {
        _componentStatus.current = false;
    }
}, []);
设置一个标志来保持
组件的状态
,如果
组件
已安装
,则
标志
值将为
,如果
组件
未安装
则标志值将为假。因此,基于此,我们可以更新
状态
。 对于标志状态,我们可以使用
useRef
保存引用

useRef
返回一个可变的ref对象,该对象的
.current
属性初始化为传递的参数(initialValue)。返回的对象将在组件的整个生命周期内持续存在。 在
useffect
中,返回一个函数,如果组件已卸载,该函数将设置组件的状态

然后在清理函数的
useffect
中,我们可以将标志设置为
false。

使用有效清除功能

useffect
挂钩允许使用清理功能。当效果不再有效时,例如当使用该效果的组件正在卸载时,将调用此函数来清除所有内容。在我们的例子中,我们可以将标志设置为false

示例:

let _componentStatus.current =  useRef(true);
useEffect(() => {
    return () => {
        _componentStatus.current = false;
    }
}, []);
在handleSubmit中,我们可以检查组件是否已安装,并基于此更新状态

function handleSubmit(e) {
    e.preventDefault();
    setLoading(true);
    Inertia.post(window.route('login.attempt'), values)
        .then(() => {
            if (_componentStatus.current) {
                setLoading(false);
            } else {
                _componentStatus = null;
            }
        })
}


在else中,将
\u componentStatus
设置为null以避免内存泄漏。

因为这是异步承诺调用,所以必须使用可变引用变量(带useRef)检查已卸载的组件,以便下一步处理异步响应(避免内存泄漏):

警告:无法对已卸载的组件执行React状态更新

在本例中应该使用两个React钩子:
useRef
useffect

例如,对于
useRef
,可变变量
\u isMounted
总是指向内存中的同一引用(而不是局部变量)

如果需要可变变量,useRef是挂钩。不像本地的 变量,React确保在每个过程中返回相同的引用 提供。如果需要,与类组件中的this.myVar相同

例如:

const login=(道具)=>{
const _isMounted=useRef(true);//初始值_isMounted=true
useffect(()=>{
return()=>{//ComponentWillUnmount在类组件中
_isMounted.current=假;
}
}, []);
函数handleSubmit(e){
e、 预防默认值();
设置加载(真);
ajaxCall=Inerty.post(window.route('login.trunt'),值)
.然后(()=>{
如果(_isMounted.current){//检查始终安装的组件
//继续治疗AJAX反应;
}
)
}
}

在同一场合,让我向您解释更多关于这里使用的React钩子的信息。另外,我将比较功能组件(React>16.8)中的React钩子和类组件中的生命周期

useEffect:大多数副作用发生在钩子内部。副作用的示例有:数据获取、设置订阅和手动更改DOM React组件。useEffect替换类组件中的许多生命周期(componentDidMount、componentDidUpate、componentWillUnmount)

  • 如果没有依赖项,useEffect的默认行为会在第一次渲染(如ComponentDidMount)和每次更新渲染(如ComponentDidUpdate)之后运行。它是这样的:
    useEffect(fnc);

  • 为useEffect提供依赖项数组将更改其生命周期。在本例中:在第一次渲染后,每次计数更改时,都会调用useEffect一次

    导出默认函数(){ const[count,setCount]=useState(0)

    }

  • 如果为依赖项放置空数组,则在第一次渲染(如ComponentDidMount)后,useEffect将只运行一次。如下所示:
    useEffect(fnc,[]);

  • <
     useEffect(fnc, [dependency1, dependency2, ...]); // dependencies array argument is optional
    
    useEffect(fnc, [count]);
    
    const login = (props) => {
      let _isMounted= true; // it isn't good because of a local variable, so the variable will be lost and re-defined on every update render
    
      useEffect(() => {
        return () => {
            _isMounted = false;  // not good
        }
      }, []);
    
      // ...
    }
    
     .then(() => {
       // Warning : memory leaks during the state update on the unmounted component <--------
       setLoading(false);
     })