7

I have a screen that makes a call to an api to fetch some data which is then displayed

An issue that I am seeing is that when I navigate away from the screen (I am using react-navigation 6.x) and then go back to it useEffect() is not being called

From what I have read so far, this is down to the value of userId not changing (I think i need to do some more reading around the useEffect() hook to understand better, maybe someone will help clear things up with this question)

import React, {useState, useEffect, useContext} from 'react';
import AppContext from '../../components/AppContext.js';

export const CreateNewEvent = () => {
  const globalContext = useContext(AppContext);
  const userId = globalContext.userInfo.id;

  useEffect(() => {
    const body = JSON.stringify({userId});
    fetch(eventTypesUrl, {
      method: 'POST',
      headers: {'Content-Type': 'application/json', Accept: 'application/json'},
      body: body,
    })
      .then(response => response.json())
      .then(json => setEventTypeData(json))
      .catch(error => console.error(error))
      .finally(() => setLoading(false));
    }, [userId]);

}

So in my scenario I am on Screen 1 (Here i can create an event which makes a request to get all event types and loads them into a select menu)

When I navigate to Screen 2 (to create an event type) and then back to Screen 1, the useEffect() hook is not called resulting in being unable to see the event type I have just created (hope that makes sense).. also notice that any data entered in Screen 1 previously still remains

I have come across this post which appears to be what I am dealing with, just a little unsure how to implement with my setup

How can I ensure that Screen 2 makes the api call when i go back and that all previous form data is cleared out?

Thanks

Richlewis
  • 15,070
  • 37
  • 122
  • 283

2 Answers2

10

At the core, React Navigation does not rerender the screen when a user navigates back to that screen for performance optimization and avoids unnecessary rerenders.

When required, They provide a useful hook to detect when screen is focused and run some side effects.

Let refactor code as below:

Top-level import 
import { useFocusEffect } from "@react-navigation/core";

// Run side effects when screen focused, navigated, or visited 

useFocusEffect(
  React.useCallback(() => {
    const body = JSON.stringify({ userId });
    fetch(eventTypesUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
      },
      body: body,
    })
      .then(response => response.json())
      .then(json => setEventTypeData(json))
      .catch(error => console.error(error))
      .finally(() => setLoading(false));

    return () => {
      // Run  somelogisx when user leave screen,
      // Cleaning caches or cancelling subscriptions
    };
  }, [userId]),
);

Note: React.useCallback is part of useFocusEffect API. The React Navigation team trying to optimize screen performance with memoization.

Pasquale
  • 389
  • 3
  • 11
Fiston Emmanuel
  • 4,242
  • 1
  • 8
  • 14
5

In React Native, when you are navigating forward then every screen is just pushed to navigation stack.

Now, when you navigate back the previous screen is popped out and the topmost screen in the stack is displayed. Since nothing(state or props) has changed in the topmost screen, it will not be re-rendered.

So you have to do some manual work.

import { useIsFocused } from "@react-navigation/native";


const isFocused = useIsFocused();

isFocused is boolean

useEffect(() => {

 if (userId && isFocused) {
   // Code which you want to execute when screen is loaded first 
   // time(and after userId is initialised) or loaded after press of 
   // back button     
 }
 
    
}, [userId, isFocused]);
Pawan Patel
  • 195
  • 1
  • 1
  • 8