I've seen a couple of close questions, but none that really answered my question. I have the following code in React Native.
# activities add/edit screen
# ...
const [activities, setActivities] = useState([]);
useEffect(() => {
const _setup = async () => {
const temp = await fetch(...); // fetching data from server with await
setActivities(temp);
// building save button
navigation.setOptions({
headerRight: () => (
<TouchableOpacity onPress={() => _submit()}>
<Text style={{ color: '#007AFF', fontSize: 18, }}>
Save
</Text>
</TouchableOpacity>
)
});
setReady(true);
};
_setup();
}, []);
So I build the headerRight button in useEffect to pass it an local _submit function, which looks like this.
const _submit = async () => {
console.log(activities);
try {
// fetch to send data to server
} catch (e) {
showError(e);
}
};
There is a FlatList on this screen which gets dynamically extended based on user interaction. All is well until the user presses the save button in the header. It always loads the activities array from the last hot refresh/render. But the FlatList re-renders ok, the array gets extended just as I want it to be. I tried using "useCallback" on the _submit function and set the dependency to "activities", but still, the header button seems to call the "initial" _submit function. The only thing that helped was to split the useEffect into two separates and one handling the re-render of the button.
// first one to fetch data on initial mound
// ...
useEffect(() => {
// I am using react-navigation and react-native-screens 2.7.0
navigation.setOptions({
headerRight: () => (
<TouchableOpacity onPress={() => _submit()}>
<Text style={{ color: '#007AFF', fontSize: 18, }}>
Save
</Text>
</TouchableOpacity>
)
});
}, [activities]);
It works fine, but somehow feels kind of hacky... I was under the impression that normal functions (like the _submit) would get re-constructed with each re-render, which would be triggered with e.g. a new array-element being pushed to the activities, no? For completion, I add elements to activities like this.
const _addActivity = () => {
const temp = [...activities];
const initActivity = {
title: '', // will be set later via TextInput
startTime: new Date(),
endTime: new Date(),
}
temp.push(initActivity);
setActivities(temp);
}