Search code examples
react-nativeasynchronousonpress

Why does header button onPress act differently than regular button onPress?


I have a method called sendResults() that makes an API call and does some array manipulation. When I call the method using a "normal" TouchableOpacity button, everything works fine. However, when I call it using a button I have placed in the App Stack header, the method does not run correctly. It feels like an async issue (?) but not sure...

Here is the code for the two buttons.

    <TouchableOpacity
      onPress={() => {
        sendResults(); // works fine
      }}
      style={styles.buttonStyle}
    >
      <Text>Save</Text>
    </TouchableOpacity>
  useEffect(() => {
    navigation.setOptions({
      headerRight: () => (
        <TouchableOpacity
          onPress={() => {
            sendResults(); // doesn't work
          }}
          style={styles.buttonStyle}
        >
          <Text>Save</Text>
        </TouchableOpacity>
      ),
    });
  }, []);

Edit: sendResults() code

  // Shows alert confirming user wants to send results to API
  const sendResults = () => {
    Alert.alert("Save Results", "Alert", [
      {
        text: "Save & Quit",
        onPress: () => postNumsAndNavigate(),
        style: "destructive",
      },
      { text: "Cancel", onPress: () => console.log("") },
    ]);
  };

  // Save Results button
  const postNumsAndNavigate = async () => {
    if (bibNums.length == 0) {
      alert("You have not recorded any results. Please try again.");
    } else if (bibNums.filter((entry) => entry == "").length > 0) {
      alert("Blank");
    } else {
      console.log("\n" + bibNums);
      await postNums();
      AsyncStorage.setItem(`done`, "true");
      navigation.navigate("Home Screen");
    }
  };

postNums() does an API call.

Edit 2: bibNums declaration

const [bibNums, setBibNums] = useState([]);


Solution

  • You set the handler of the navigation button only once because your useEffect doesn't have any dependency; it runs only when the component is mounted, it captures an old reference of sendResults. sendResults changes every time postNumsAndNavigate and bibNums change. Add sendResults to the dependency array to update the navigation button handler every time sendResults changes.

    useEffect(() => {
    ...
    }, [sendResults])
    

    It works correctly for the TouchableOpacity because you are assigning the handler on every render.

    onPress={() => {sendResults()}}