Reputation: 223
I'm having a problem. been browsing some questions here but seems doesn't work for me.
I'm getting this error in my three pages when I'm using the useEffect.
This is the code of my useEffect
const UserDetailsPage = () => {
const classes = useStyles()
const [userData, setUserData] = useState({
_id: "",
name: "",
phone: "",
address: "",
birthdate: "",
gender: "",
messenger: "",
photo: "",
email: "",
})
const [open, setOpen] = useState(false)
const [loaded, setLoaded] = useState(false)
const { height, width } = useWindowDimensions()
const {
_id,
name,
phone,
address,
photo,
gender,
messenger,
birthdate,
email,
} = userData
useEffect(() => {
const user = getUser()
getUserById("/user/" + user.userId, user.token)
.then((data) => {
setUserData(data)
setLoaded(true)
})
.catch((error) => {
console.log(error)
})
}, [])
Upvotes: 2
Views: 123
Reputation: 13
Don't use async tasks in useEffect. Define an async function and call in your useEffect.
Example:
const getSTH = async() =>{
getUserById("/user/" + user.userId, user.token)
.then((data) => {
if(mounted) { // set state only when component is mounted
setUserData(data)
setLoaded(true)
}
})
.catch((error) => {
console.log(error)
})
}
useEffect (()=>{
getSTH();
},[])
I think this approach will help you.
Upvotes: -1
Reputation: 72
This happens when your component is unmounting before setting your state. Try this code below to check if the component is mounted or not.
useEffect(() => {
let isMounted = true; // add a flag to check component is mounted
getUserById("/user/" + user.userId, user.token)
.then((data) => {
if(mounted) { // set state only when component is mounted
setUserData(data)
setLoaded(true)
}
})
.catch((error) => {
console.log(error)
})
return () => { isMounted = false }; // cleanup toggles value, if unmounted
}, []);
Upvotes: 1
Reputation: 202618
Short of getUserById
returning a cancel token to cancel any inflight network requests, or an "unsubscribe" method, you can use a React ref to track if the component is still mounted or not, and not enqueue the state update if the component has already unmounted.
const isMountedRef = React.useRef(false);
useEffect(() => {
isMountedRef.current = true;
return () => isMountedRef.current = false;
}, []);
useEffect(() => {
const user = getUser();
getUserById("/user/" + user.userId, user.token)
.then((data) => {
if (isMountedRef.current) {
setUserData(data);
setLoaded(true);
}
})
.catch((error) => {
console.log(error);
});
}, []);
Upvotes: 3
Reputation: 2962
This is because of the async call in useEffect
finishing and then attempting to setState
after the page is no longer in focus.
It can be avoided by refactoring the useEffect
like so:
useEffect(() => {
// created a boolean to check if the component is mounted, name is arbitrary
let mounted = true;
const user = getUser();
getUserById("/user/" + user.userId, user.token)
.then((data) => {
// only setState if mounted === true
if (mounted) {
setUserData(data);
setLoaded(true);
}
})
.catch((error) => {
console.log(error);
});
// set mounted to false on cleanup
return () => {
mounted = false;
};
}, []);
What's different here is that I use a mounted
boolean to check if the page is currently mounted. By wrapping the setState
call inside an if state, I can check if it's safe to setState
, therefore avoiding the error.
Upvotes: 1