Reputation:
I am using axios to get some data from my API but all the request are not in useEffect function. Even more - I am not using useEffect at whole.
Here are parts of my code:
JSX:
<form onSubmit={onSubmitLogin}>
<div className="form sign-in">
<h2>Hello again,</h2>
<div className="div-label">
<label>
<span>Email</span>
<input type="email" onChange={onLoginEmailChange} />
</label>
</div>
<div className="div-label">
<label>
<span>Password</span>
<input type="password" onChange={onLoginPasswordChange} />
</label>
</div>
<p className="forgot-pass">Forgot password?</p>
{loading && (
<img
alt="svg"
className="loading-img"
align="middle"
width={35}
height={35}
src={mySvg}
/>
)}
{!loading && (
<input className="submit" type="submit" value="Sign In" />
)}
So this is calling:
const onSubmitLogin = e => {
e.preventDefault();
setLoading(true);
axios
.get(
`http://myapiURL/?email=${loginEmail}&password=${loginPassword}`
)
.then(res => {
console.log(res);
if (res.status === 200) {
console.log("here");
history.push({
pathname: "/dashboard",
state: res.data
});
setLoading(false);
}
})
.catch(e => {
console.log(e);
});
};
This is working and it giving me data but in browser I see this error:
index.js:1375 Warning: Can't perform a React state update on an unmounted component. 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 Login (created by Context.Consumer)
I found a lot about this but all of it was related that they put their request methods in useEffect.
P.S.: By the way I am using React hooks (useState but not useEffect in this component)
Upvotes: 0
Views: 2977
Reputation: 496
this problem may occurs if the component is unmounted before async function finish and try to set some state var
to fix this you can do something like:
React.useEffect(() => {
let isSubscribed = true;
axios
.get(
`http://myapiURL/?email=${loginEmail}&password=${loginPassword}`
)
.then(res => {
console.log(res);
if (res.status === 200) {
history.push({
pathname: "/dashboard",
state: res.data
});
// check if this component still mounted
if (isSubscribed) {
setLoading(false);
}
}
});
return () => (isSubscribed = false);
}, []);
Upvotes: 0
Reputation: 2648
You are setting a state for unmounted component so you have to call setLoading
before history.push
:
const onSubmitLogin = e => {
e.preventDefault();
setLoading(true);
axios
.get(
`http://myapiURL/?email=${loginEmail}&password=${loginPassword}`
)
.then(res => {
console.log(res);
if (res.status === 200) {
console.log("here");
setLoading(false);
history.push({
pathname: "/dashboard",
state: res.data
});
}
})
.catch(e => {
console.log(e);
});
};
Upvotes: 0
Reputation: 126
On your onSubmitLogin you're pushing to another pathname, which provokes the components to unmount and after that, you're trying to update a state from a component already unmounted (that setLoading(false) you have after the history.push).
you can either setLoading(false) before the history push or remove the setLoading from there and create an useEffect to set the loading status to false on the cleaning cycle of that. like:
useEffect(() => {
return () => {
setLoading(false);
}
}, [])
The return of useEffect will execute before changing to another component, like the ComponentWillUnmount lifecycle.
Upvotes: 1