Home > Net >  State does not update when returning to screen inside navigator
State does not update when returning to screen inside navigator

Time:03-24

I'm trying to set the initialRouteName depending on a condition. On the first run the state is set correctly and I'm going to the intended screen but when I go back/away from the screen and return to it, the useEffect does not run again and I'm seeing the previous screen.

I'm not sure how to handle this correctly inside the navigator.

function ProductNavigator() {
let [initialRoute, setInitialRoute] = useState<string | null>(null);

useEffect(() => {
  let getProducts = async () => {
    let products = await AsyncStorage.getItem('product_list');
    let isSingleProduct = products.length === 1;

    
    setInitialRoute(isSingleProduct);
    
  };

  getProducts();
});

return (
  <NativeStack.Navigator
    screenOptions={{ headerShown: false }}
    initialRouteName={initialRoute}
  >
  <NativeStack.Screen
    name="SingleProduct"
    component={SingleProductScreen}
  />
  <NativeStack.Screen
    name="MultiProducts"
    component={MutliProductScreen}
  />
  <NativeStack.Screen
    name="SomeOtherScreen"
    component={SomeOtherScreen}
  />
</NativeStack.Navigator>
);
}

UPDATE

I used the suggestion from the answer below and have the following result. When I log each step I can see that the state ends up where I need it but the Navigator ignores the initialRouteName I set and shows the first screen in the stack.

let navigation = useNavigation();
let [initialRoute, setInitialRoute] = useState<string | null>(null);

useFocusEffect(
  useCallback(() => {
    let getProducts = async () => {
      let products = await AsyncStorage.getItem("product_list");
      let route = products.length > 1 ? "MultiProducts" : "SingleProduct";

      setInitialRoute(route);
    };

    getProducts();
  }, [])
);

useEffect(() => {
  let unsub = navigation.addListener('blur', () => {
    setInitialRoute(null);
  });

  return unsub;
}, []);

return initialRoute != null ? (
  <NativeStack.Navigator
    screenOptions={{ headerShown: false }}
    initialRouteName={initialRoute}
  >
    <NativeStack.Screen
      name="SingleProduct"
      component={SingleProductScreen}
    />
    <NativeStack.Screen name="MultiProducts" component={MutliProductScreen} />
    <NativeStack.Screen name="SomeOtherScreen" component={SomeOtherScreen} />
  </NativeStack.Navigator>
) : (
    <NativeStack.Navigator
    screenOptions={{ headerShown: false }}
  >
      <NativeStack.Screen name="loading" component={LoadingScreen} />
  </NativeStack.Navigator>
);

CodePudding user response:

UseEffects will only run when the screen is first mounted. In your case the screen doesn't unmount when you go to another screen but basically just stays in the background. To fix this, use the useFocusEffect in combination with a useCallback. This Hook will be called every time the screen comes in focus.

useFocusEffect(
React.useCallback(() => {
  // do the stuff you wanna do

  return () => {}; // This will be called when the screen is unfocused.
                   // I don't think you need that but I included it anyway
}, []));
  • Related