![](/img/trans.png)
[英]How to fix Can't perform a React state update on an unmounted component
[英]Fix "Can't perform a React state update on an unmounted component" error
当我尝试推送到我的 Web 应用程序中的新页面时,下面的代码给出了一个控制台错误:
警告:无法对卸载的组件执行 React 状态更新。 这是一个空操作,但它表明您的应用程序中存在内存泄漏。 要修复,请取消 useEffect 清理函数中的所有订阅和异步任务。 在 PasswordResetPage(由 Context.Consumer 创建)
您会注意到,在注释掉的代码中,我尝试使用useEffect
因为这是大多数 stackoverflow 答案所指向的内容。 但是,错误仍然存在。 如何在这种情况下使用history.push
并摆脱错误?
import React, { useState /* , useEffect */ } from 'react'
import useForm from 'react-hook-form'
import Logo from '../assets/images/logo-icon-orange.png'
import TextInput from '../components/TextInput'
import Footer from '../components/Footer'
import AnimatedButton from '../components/AnimatedButton'
import logger from '../logger'
import { sleep } from '../utils/promise'
import PasswordResetSchema from './validation/PasswordResetSchema'
const PasswordResetPage = ({ history }) => {
const [isSubmitting, setSubmitting] = useState(false)
// const [isDone, setDone] = useState(false)
const { register, handleSubmit, errors } = useForm({
validationSchema: PasswordResetSchema,
})
const onSubmit = async data => {
setSubmitting(true)
await sleep(2000)
logger.info('form data', data)
// setDone(true)
history.push('/confirmation')
}
// useEffect(() => {
// if (isDone) {
// history.push('/confirmation')
// }
// })
return (
<form onSubmit={handleSubmit(onSubmit)} noValidate>
<div className="text-center mb-4">
<img className="mb-4" src={Logo} alt="Striver" width={72} />
<h1 className="h3 mb-3 font-weight-normal">Password reset</h1>
<p>Enter your email address below and we will send you instructions on how you can reset your password.</p>
</div>
<div className="form-label-group">
<TextInput type="email" id="email" register={register} label="Email address" errors={errors} />
</div>
<AnimatedButton actionTitle="Next" isSubmitting={isSubmitting} />
<Footer />
</form>
)
}
export default PasswordResetPage
看看这是否适合你:
代码沙盒与工作示例:
https://codesandbox.io/s/reactrouteranswerso-817bp
const onSubmit = async data => {
setSubmitting(true)
await sleep(2000)
logger.info('form data', data)
setDone(true)
}
useEffect(() => {
if (isDone) {
history.push('/confirmation')
}
},[isDone]);
CodeSandbox 上的工作代码:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import "./styles.css";
function App() {
const [user, setUser] = useState(null);
function doLogin() {
console.log("Inside do login...");
setUser("someUserID");
}
function doLogout() {
console.log("Inside do logout...");
setUser(null);
}
return (
<Router>
<AllRoutes user={user} doLogin={doLogin} doLogout={doLogout} />
</Router>
);
}
function AllRoutes(props) {
console.log("Rendergin AllRoutes...");
// console.log(props);
return (
<Switch>
<Route exact path="/" component={Component1} />
<Route exact path="/comp2" component={Component2} />
</Switch>
);
}
function Component1(props) {
const [isDone, setIsDone] = useState(false);
useEffect(() => {
if (isDone) {
props.history.push("/comp2");
}
}, [isDone, props.history]);
return (
<React.Fragment>
<div>Component1</div>
<button onClick={() => setIsDone(true)}>Submit</button>
</React.Fragment>
);
}
function Component2(props) {
const [goBack, setGoBack] = useState(false);
useEffect(() => {
if (goBack) {
props.history.push("/");
}
}, [goBack, props.history]);
return (
<React.Fragment>
<div>Component2</div>
<button onClick={() => setGoBack(true)}>Go Back</button>
</React.Fragment>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
我相信await sleep(2000)
是实际 API 调用的替代品。
API 调用以及history.push
是副作用,因此应该放在useEffect
。
尝试这个:
const PasswordResetPage = ({ history }) => {
const [formData, setFormData] = useState(null);
// ...
const onSubmit = async data => {
setFormData(data);
}
useEffect(() => {
logger.info('form data', formData);
sleep(2000).then(() => history.push('/confirmation'););
}, [formData]);
// ...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.