1

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);
    }
clash
  • 427
  • 4
  • 11
  • Try use React context api. – Vahid Alimohamadi May 10 '20 at 06:45
  • How could the context api help me here? – clash May 10 '20 at 07:47
  • It helps you to fetch data only when the stored context value is null or empty. It will renders twice only on first render. – Vahid Alimohamadi May 10 '20 at 08:52
  • Could you give a code example? I don't really get what you mean. But there is still the problem that when I push a new element into the array, the submit still is not catching that change. The initial setup is not the main problem here. – clash May 10 '20 at 09:28
  • it's not hacky, that's how it's supposed to be. there's no difference between functions or other data. if you use something inside an effect, you need to pass them as dependencies or it'll use the older version. you should use this eslint plugin which will suggest you what to put in dependencies https://www.npmjs.com/package/eslint-plugin-react-hooks – satya164 May 10 '20 at 17:31
  • @clash How did you solve this ? – Freduah Gideon Dec 24 '21 at 09:21
  • @FreduahGideon I did not change anything, so I did solve it as written above, basically rebuilding the Save button in the navigation.setOptions on each useEffect-cycle. I worked all along, just felt kind of weird to rebuild the button. But it works – clash Jan 31 '22 at 15:22

0 Answers0