I have a simplified react native app here that makes a network call and sets a flag when it loads. There is a button onPress handler which calls another method doSomething, both methods which are in a useCallback and the dependency arrays are correct as per the exhaustive-deps plugin in vscode.
When the app loads I can see the isInitialized flag is set to true, however pressing the button afterwards shows the flag is still false in the doSomething method. It seems like the useCallback methods are not being regenerated according to their dependency arrays in this situation.
import React, {useEffect, useState, useCallback} from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
export default function App() {
const [isInitialized, setIsInitialized] = useState(false);
useEffect(() => {
fetch("http://www.google.com").then(() => setIsInitialized(true) );
}, []);
const onPress = useCallback(() => {
doSomething();
}, [doSomething]);
const doSomething = useCallback(() => {
console.log("doSomething", { isInitialized });
}, [isInitialized]);
return (
<View style={{flex:1, justifyContent:"center", alignItems:"center"}}>
{isInitialized &&
<Text>Initialized</Text>
}
<TouchableOpacity onPress={onPress} style={{padding:30, borderWidth:1}}>
<Text>Press Me</Text>
</TouchableOpacity>
</View>
);
}
Can someone please explain why this happens? Note that the stale state only happens when the flag is set after the network call, and only happens with two hops between methods with useCallback(). If the button onPress is set to doSomething directly, then the flag shows correctly as true.
I am using useCallback in this way all over my code, and I'm afraid of finding stale state in unexpected places due to not understanding something that's going on here.
Function doSomething is undefined
when you are passing it as a dependency to useCallback, so function doesn't change with isInitialized
. Move declaration of doSomething above onPress. Using useCallback everywhere may not be the best idea, but I don't know your use case and I hope you measured performance and gains :)