React Native useEffect Hooks and React Navigation setParams doesn't update on loading

Viewed 2717

How come my React Navigation setParams doesn't update data on component mounted?

const NewScreen = props => {
  const [extraInfo, setExtraInfo] = useState({
    title: '',
    description: '',
  });
  const [mediaArray, setMediaArray] = useState(null);
  const [someData, setSomeData] = useState({});

  const grabData = useCallback(() => {
    return axios
      .get('url')
      .then(res => {
        /* does some data grabbing for setSomeData and setMediaArray */

        setSomeData({
          data1,
          data2,
          data3,
        });
        setMediaArray(media);
      })
      .catch(err => console.log('axios catch err', err));
  }, []);

  /* ... more data grabbing for extraInfo */

  useEffect(() => {
    grabData();
    props.navigation.setParams({
      mutate: props.mutate,
      title: extraInfo.title,
      description: extraInfo.description,
      newDataForAray: mediaArray,
      ...someData,
    });
  }, [grabData]);

  return (
    <KeyboardAvoidingView behavior="padding" style={styles.keyboardView}>
      ...
    </KeyboardAvoidingView>
  );
};

NewScreen.navigationOptions = props => {
  const {mutate, title, description, newDataForAray} = props.navigation.state.params;
  const handleSubmit = () => {
    mutate({
      variables: {
        title,
        description,
      },
    });
  };
  return {
    headerRight: () => (
      <TouchableOpacity
        onPress={() => handleSubmit()}
        style={{marginRight: 10}}>
        <Text>Done</Text>
      </TouchableOpacity>
    ),
  };
};

const mutation = gql`
  mutation someMutation(
    ...
  ) {
    ...
  }
`;

export default graphql(mutation)(withNavigation(NewScreen));

So on loading, I'm able to get data through axios. But when component mounts, the data in prop.navigation.setParams doesn't get populated. If I add someData, mediaArray or extraInfo, into the array of the useEffect callback, it will infinitely loop, rerendering my component, but the data in navigation.state will finally populate.

I want to be able to pass the values into navigation state so I can use it in the header

1 Answers

With your current setup, grabData is going to pull your data but won't refresh someData, mediaArray, etc until the next render. But, your next render won't run since your useEffect's dependency array won't trigger.

You could use two useEffects with one reserved for grabData and other for props.nav. Better yet, update props.nav within grabData.


update reflecting comment

Media or somedata value doesn't change immediately. Thus, reference the same media or somedata pulled by your api to your setParams

 const grabData = useCallback(() =>
  axios
  .get('url')
  .then(res => {
    /* does some data grabbing for setSomeData and setMediaArray */

    const someData = {
      data1,
      data2,
      data3,
    };
    setSomeData(someData);
    setMediaArray(media);
    const paramsTest = {
       mutate: props.mutate,
       title: extraInfo.title,
       description: extraInfo.description,
       newDataForAray: media,
       ...someData,
     };
     console.log({ paramsTest }); // used to confirm values provided to nav
     props.navigation.setParams(paramsTest);
  })
  .catch(err => console.log('axios catch err', err)), [props.navigation.setParams]);
Related