The code below gives a console error when I try to push to a new page in my web application:
Warning: Can't perform a React state update on an unmounted ponent. 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. in PasswordResetPage (created by Context.Consumer)
You will have noticed in the code that is mented out that I've tried to use useEffect
as this is what most stackoverflow answers points to. However, the error is still present. How can I use history.push
in this context and get rid of the error?
import React, { useState /* , useEffect */ } from 'react'
import useForm from 'react-hook-form'
import Logo from '../assets/images/logo-icon-orange.png'
import TextInput from '../ponents/TextInput'
import Footer from '../ponents/Footer'
import AnimatedButton from '../ponents/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
The code below gives a console error when I try to push to a new page in my web application:
Warning: Can't perform a React state update on an unmounted ponent. 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. in PasswordResetPage (created by Context.Consumer)
You will have noticed in the code that is mented out that I've tried to use useEffect
as this is what most stackoverflow answers points to. However, the error is still present. How can I use history.push
in this context and get rid of the error?
import React, { useState /* , useEffect */ } from 'react'
import useForm from 'react-hook-form'
import Logo from '../assets/images/logo-icon-orange.png'
import TextInput from '../ponents/TextInput'
import Footer from '../ponents/Footer'
import AnimatedButton from '../ponents/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
Share
Improve this question
asked Jun 15, 2019 at 6:51
Andre GalloAndre Gallo
2,2695 gold badges24 silver badges46 bronze badges
1
- Possible duplicate of Can't perform a React state update on an unmounted ponent? – Vahid Al Commented Jun 15, 2019 at 9:25
2 Answers
Reset to default 6See if that works for you:
Code SandBox with working example:
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]);
Working code on 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="/" ponent={Component1} />
<Route exact path="/p2" ponent={Component2} />
</Switch>
);
}
function Component1(props) {
const [isDone, setIsDone] = useState(false);
useEffect(() => {
if (isDone) {
props.history.push("/p2");
}
}, [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);
I believe await sleep(2000)
is a replacement for actual API call.
API calls as well as history.push
are side effects thus should be places in useEffect
.
Try this:
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]);
// ...
}