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 PokemonListItem (at PokemonList.jsx:148)
Okay so I know this is a common issue and the solution should be quite simple. I just don't know how to implement it to my code.
I'm making a kind of Pokédex for mobile using React-Native and PokéAPI. I'm not sure where the leak lies, so more experienced developers, please help.
export default function PokemonListItem({ url, Favorite }) {
const [pokemondata, setData] = React.useState({});
const [dataReady, setReady] = React.useState(false);
const [isFavorite, setFavorite] = React.useState(false);
const favoriteStatus = (bool) => {
setFavorite(bool);
};
const getData = async () => {
await fetch(url)
.then((res) => res.json())
.then((data) => setData(data));
setReady(true);
};
React.useEffect(() => {
getData();
}, []);
more code...
const renderItem = ({ item }) => (
<TouchableHighlight
style={{ borderRadius: 10 }}
underlayColor="#ffc3c2"
onPress={() => {
navigation.navigate("Pokémon Details", {
url: item.url,
});
}}
>
<PokemonListItem url={item.url} Favorite={FavoriteButton} />
</TouchableHighlight>
);
if you need to see the full code, you can visit the repository .
An approach seems to be to maintain a variable to see whether or not the component is still mounted or not, which feels smelly to me ( React-hooks. Can't perform a React state update on an unmounted component )- but anyway this is how I would see it in your code...
let isMounted;
const getData = async () => {
await fetch(url)
.then((res) => res.json())
.then((data) => { if(isMounted) setData(data)});
setReady(true);
};
React.useEffect(() => {
isMounted = true;
getData();
return () => {
isMounted = false;
}
}, []);
Try this
React.useEffect(() => { (async function onMount() { await fetch(url) .then((res) => res.json()) .then((data) => setData(data)); setReady(true); })(); }, []);
Similar to what was mentioned earlier, the key point being wrapping your state update setReady()
in an if (mounted){}
block .
let mounted = true;
in your effect that has the async callreturn () => { mounted = false }
if (mounted) { setState(...)}
useEffect(() => {
let mounted = true;
const apiRequest = async (setReady) => {
let response;
try {
response = await APICall();
if (mounted) {
setReady(response.data);
}
} catch (error) {}
}
apiRequest();
return () => { mounted = false;}
})
https://codesandbox.io/s/upbeat-easley-kl6fv?file=/src/App.tsx
If you remove the || true
|| true
call and refresh you'll see that the error for mem leak is gone.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.