我是使用React的新手,所以这可能真的很容易实现,但是即使我做了一些研究,也无法自己解决。如果这太蠢了,请原谅我。
我正在将Inertia.js与Laravel(后端)和React(前端)适配器一起使用。如果您不知道惯性,则基本上是:
Inertia.js使您可以使用经典的服务器端路由和控制器快速构建现代的单页React,Vue和Svelte应用程序。
我正在做一个简单的登录页面,该页面具有一种表单,提交后将执行POST请求以加载下一页。似乎工作正常,但在其他页面上,控制台显示以下警告:
警告:无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要修复,请取消使用useEffect清理功能中的所有订阅和异步任务。
登录(由Inertia创建)
相关代码(为了避免不相关的行,我对其进行了简化):
import React, { useEffect, useState } from 'react'
import Layout from "../../Layouts/Auth";
{/** other imports */}
const login = (props) => {
const { errors } = usePage();
const [values, setValues] = useState({email: '', password: '',});
const [loading, setLoading] = useState(false);
function handleSubmit(e) {
e.preventDefault();
setLoading(true);
Inertia.post(window.route('login.attempt'), values)
.then(() => {
setLoading(false); // Warning : memory leaks during the state update on the unmounted component <--------
})
}
return (
<Layout title="Access to the system">
<div>
<form action={handleSubmit}>
{/*the login form*/}
<button type="submit">Access</button>
</form>
</div>
</Layout>
);
};
export default login;
现在,我知道我必须执行清除功能,因为请求的承诺就是生成此警告的原因。我知道我应该使用,useEffect
但在这种情况下我不知道如何应用。我已经看到了一个值更改的示例,但是如何在这种调用中执行呢?
提前致谢。
根据要求,此组件的完整代码为:
import React, { useState } from 'react'
import Layout from "../../Layouts/Auth";
import { usePage } from '@inertiajs/inertia-react'
import { Inertia } from "@inertiajs/inertia";
import LoadingButton from "../../Shared/LoadingButton";
const login = (props) => {
const { errors } = usePage();
const [values, setValues] = useState({email: '', password: '',});
const [loading, setLoading] = useState(false);
function handleChange(e) {
const key = e.target.id;
const value = e.target.value;
setValues(values => ({
...values,
[key]: value,
}))
}
function handleSubmit(e) {
e.preventDefault();
setLoading(true);
Inertia.post(window.route('login.attempt'), values)
.then(() => {
setLoading(false);
})
}
return (
<Layout title="Inicia sesión">
<div className="w-full flex items-center justify-center">
<div className="w-full max-w-5xl flex justify-center items-start z-10 font-sans text-sm">
<div className="w-2/3 text-white mt-6 mr-16">
<div className="h-16 mb-2 flex items-center">
<span className="uppercase font-bold ml-3 text-lg hidden xl:block">
Optima spark
</span>
</div>
<h1 className="text-5xl leading-tight pb-4">
Vuelve inteligente tus operaciones
</h1>
<p className="text-lg">
Recoge data de tus instalaciones de forma automatizada; accede a información histórica y en tiempo real
para que puedas analizar y tomar mejores decisiones para tu negocio.
</p>
<button type="submit" className="bg-yellow-600 w-40 hover:bg-blue-dark text-white font-semibold py-2 px-4 rounded mt-8 shadow-md">
Más información
</button>
</div>
<div className="w-1/3 flex flex-col">
<div className="bg-white text-gray-700 shadow-md rounded rounded-lg px-8 pt-6 pb-8 mb-4 flex flex-col">
<div className="w-full rounded-lg h-16 flex items-center justify-center">
<span className="uppercase font-bold text-lg">Acceder</span>
</div>
<form onSubmit={handleSubmit} className={`relative ${loading ? 'invisible' : 'visible'}`}>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-semibold mb-2" htmlFor="email">
Email
</label>
<input
id="email"
type="text"
className=" appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 outline-none focus:border-1 focus:border-yellow-500"
placeholder="Introduce tu e-mail.."
name="email"
value={values.email}
onChange={handleChange}
/>
{errors.email && <p className="text-red-500 text-xs italic">{ errors.email[0] }</p>}
</div>
<div className="mb-6">
<label className="block text-gray-700 text-sm font-semibold mb-2" htmlFor="password">
Contraseña
</label>
<input
className=" appearance-none border border-red rounded w-full py-2 px-3 text-gray-700 mb-3 outline-none focus:border-1 focus:border-yellow-500"
id="password"
name="password"
type="password"
placeholder="*********"
value={values.password}
onChange={handleChange}
/>
{errors.password && <p className="text-red-500 text-xs italic">{ errors.password[0] }</p>}
</div>
<div className="flex flex-col items-start justify-between">
<LoadingButton loading={loading} label='Iniciar sesión' />
<a className="font-semibold text-sm text-blue hover:text-blue-700 mt-4"
href="#">
<u>Olvidé mi contraseña</u>
</a>
</div>
<div
className={`absolute top-0 left-0 right-0 bottom-0 flex items-center justify-center ${!loading ? 'invisible' : 'visible'}`}
>
<div className="lds-ellipsis">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</form>
</div>
<div className="w-full flex justify-center">
<a href="https://optimaee.com">
</a>
</div>
</div>
</div>
</div>
</Layout>
);
};
export default login;
因为这是异步诺言调用,所以您必须使用 一个可变的引用变量(带有useRef) 来检查已卸载的组件,以进行异步响应的下一个处理(避免内存泄漏):
警告:无法在已卸载的组件上执行React状态更新。
在这种情况下,您应该使用两个React Hook:useRef
和useEffect
。
useRef
例如,使用,可变变量_isMounted
始终指向内存中的同一引用 (而不是局部变量)
*如果需要可变变量, *useRef 是挂钩。与局部变量不同,React确保在每次渲染期间都返回相同的引用。如果需要,与
类组件中的this.myVar* 相同 *
范例:
const login = (props) => {
const _isMounted = useRef(true); // Initial value _isMounted = true
useEffect(() => {
return () => { // ComponentWillUnmount in Class Component
_isMounted.current = false;
}
}, []);
function handleSubmit(e) {
e.preventDefault();
setLoading(true);
ajaxCall = Inertia.post(window.route('login.attempt'), values)
.then(() => {
if (_isMounted.current) { // Check always mounted component
// continue treatment of AJAX response... ;
}
)
}
}
同时,让我向您解释有关此处使用的React Hooks的更多信息。另外,我将功能组件中的React Hook(反应>
16.8)与类组件中的LifeCycle进行比较。
useEffect :大多数副作用发生在钩子内部。副作用的示例包括:数据获取,设置订阅以及手动更改DOM
React组件。useEffect替换了类Component中的许多生命周期(componentDidMount,componentDidUpate,componentWillUnmount)
useEffect(fnc, [dependency1, dependency2, ...]); // dependencies array argument is optional
如果您没有依赖关系,则useEffect的默认行为在第一个渲染 (例如ComponentDidMount) 之后和每个更新渲染 (例如ComponentDidUpdate) 之后运行。就像那样 :useEffect(fnc);
将依赖项数组赋予useEffect将更改其生命周期。在这个例子中:useEffect将在第一个渲染之后被调用一次,并且每次计数改变时
导出默认函数(){const [count,setCount] = useState(0);
useEffect(fnc, [count]);
}
如果将空数组放置为依赖项,则useEffect将在第一个渲染 (如ComponentDidMount) 之后仅运行一次。就像那样 :useEffect(fnc, []);
为了防止资源泄漏,必须在挂钩的生命周期结束时处置所有 组件(例如ComponentWillUnmount) 。例如,对于空的依赖关系数组,将在组件卸载后调用返回的函数。就像那样 :
useEffect(()=> {return fnc_cleanUp; //
fnc_cleanUp将取消所有订阅和异步任务(例如:clearInterval)},[]);
useRef :返回 一个可变的ref对象, 其 .current
属性已初始化为传递的参数(initialValue)。返回的对象将在组件的整个生命周期内保持不变。
示例:对于上述问题,我们不能在此处使用局部变量,因为它将在每次更新渲染时丢失并重新启动。
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
}
}, []);
// ...
}
因此,结合 useRef 和 useEffect ,我们可以完全清除内存泄漏。
您可以阅读更多有关React Hooks的链接:
[ZH] https://medium.com/@sdolidze/the-iceberg-of-react-hooks-
af0b588f43fb
[FR] https://blog.soat.fr/2019/11/react-hooks-par-
lexemple/
问题内容: 我只是为了好玩而创建了一个项目,该项目创建了大约5 GB的内存,并且没有删除它。只要应用程序正在运行,“内存泄漏”就在那里。我第二次关闭应用程序后,内存在2秒内恢复正常,就好像我的程序从未运行过一样。因此必须提出问题。 Windows 7完成处理后,是否会清理掉程序造成的内存泄漏? 所有Windows版本都这样做吗? Linux和Mac OS X环境会这样做吗? 问题答案: 当程序终止
上下文:我有一个从父“启动器”程序运行的Swing JFrame应用程序。启动器负责检查更新和实际更新应用程序。因此,它在儿童类加载器中运行该应用程序,最终在新的jar可用时重新启动它。 Boes有人对正在发生的事情有洞察力吗?我是不是应该做点别的事情来把一切都清理干净?
问题内容: 在我的react组件中,我试图在ajax请求进行时实现一个简单的微调器-我使用状态来存储加载状态。 由于某种原因,我的React组件下面的这段代码抛出此错误 只能更新已安装或正在安装的组件。这通常意味着您在未安装的组件上调用了setState()。这是无人值守。请检查未定义组件的代码。 如果我摆脱了第一个setState调用,错误就会消失。 问题是,当应该已经安装了组件时(为什么从co
出现此错误,JSP页面变为空白(白色): Jan9, 2013 7:30:39PMorg.apache.catalina.loader.WebappClassLoader clearThreadLocalMap SEVERE:Web应用程序[/MyWebApp]创建了一个ThreadLocal,其中键的类型为[net.sourceforge.jtds.jdbc.DateTime1美元](值[net
我在Eclipse中使用Lifeay IDE创建了一个新项目(带有插件Portlet类型和JSF2.x.x Portlet框架的Liferay项目)。我没有做任何更改,将project添加到LiferayV6.1CE服务器(Tomcat7)并启动了这个服务器。 不幸的是,我得到了这个错误(portlet未注册)。 (...)09:05:08,828信息[ContainerBackgroundPro
我尝试用一个大表(大约一万条记录)中的记录填充JdbcRowSet。我尝试了两个变体(参见下面的代码): 创建连接对象,使用JdbcRowSetImpl(connection)实例化,在循环中执行查询。 使用JdbcRowSetImpl(DriverManager.GetConnection(“jdbc:....”)实例化,在循环中执行查询。 第一个变体会导致内存泄漏,直到堆满为止。第二个变体没有