Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The 'navigation' object hasn't been initialized yet #6879

Closed
har2008preet opened this issue Feb 18, 2020 · 57 comments
Closed

The 'navigation' object hasn't been initialized yet #6879

har2008preet opened this issue Feb 18, 2020 · 57 comments

Comments

@har2008preet
Copy link

har2008preet commented Feb 18, 2020

Current Behavior

  • Navigating by creating Service.

Expected Behavior

  • Navigation should happen

How to reproduce
app.tsx

let App = inject("globalStore")(observer((props) => {

    enableScreens();

    React.useEffect(() => {

        isMountedRef.current = true;
        console.log("isNavigation Mounted: ", isMountedRef.current)

        return () => isMountedRef.current = false;
    }, [])

 

    return (

        <NavigationContainer ref={navigationServiceRef}>
            <RootNavigator
                {...this.props}/>
        </NavigationContainer>

    );
}));
export default App;

NavigationService.ts

import { NavigationActions, StackActions } from '@react-navigation/compat';

import * as React from 'react';

export const isMountedRef = React.createRef();

export const navigationServiceRef = React.createRef();

export function navigate(name, params) {
    if (isMountedRef.current && navigationServiceRef.current) {
        console.log("Navigation Should happen")
        try {
            navigationServiceRef.current.navigate("App", params);
        }catch(e){
            console.log("NavigationDebug Error: ", e)
        }
    } else {

    }
}

export default {
    navigate
};

I am getting:

NavigationDebug Error: Error: The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. You can ensure that all navigators have mounted after the callback to 'useEffect' is called in your root component. See https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html#handling-initialization for more details.
at dispatch (BaseNavigationContainer.tsx:202)
at Object.acc. [as navigate] (BaseNavigationContainer.tsx:245)
at Object.navigate (NavigationService.ts:34)
at SplashScreen.redirectUser (splash-screen.tsx:232)
at SplashScreen.proxiedMethod (createPrototypeProxy.js:44)
at _callee2$ (splash-screen.tsx:296)
at tryCatch (runtime.js:45)
at Generator.invoke [as _invoke] (runtime.js:271)
at Generator.prototype. [as next] (runtime.js:97)
at tryCatch (runtime.js:45)

Your Environment

software version
iOS or Android Android 10
@react-navigation/native 5.0.5
react-native 0.60.0
expo NA
node v13.6.0
npm or yarn yarn 1.21.1

NOTE: I am upgrading from 4.x.x via https://reactnavigation.org/docs/en/upgrading-from-4.x.html and https://reactnavigation.org/docs/en/compatibility.html

@github-actions
Copy link

Hey! Thanks for opening the issue. Can you provide a minimal repro which demonstrates the issue? Posting a snippet of your code in the issue is useful, but it's not usually straightforward to run. A repro will help us debug the issue faster. Please try to keep the repro as small as possible. The easiest way to provide a repro is on snack.expo.io. If it's not possible to repro it on snack.expo.io, then you can also provide the repro in a GitHub repository.

@AtlantisPleb
Copy link

Encountered the same on RN 61.5. My terribly hacky workaround was to wrap navigate() in a setTimeout with 100 ms delay.

@satya164
Copy link
Member

Can you provide a repro to show when the happens?

@mohanadarafe

This comment has been minimized.

@har2008preet
Copy link
Author

sure @satya164 , will create snack and share it.

@satya164
Copy link
Member

Closing due to no repro. Please comment with repro to re-open.

@alexandra-oshmyanskaya
Copy link

alexandra-oshmyanskaya commented Mar 26, 2020

@uusa35

This comment has been minimized.

@uusa35
Copy link

uusa35 commented Apr 10, 2020

https://reactnavigation.org/docs/navigating-without-navigation-prop/#handling-initialization

i already did what mentioned above but still same error occurs

The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted,

@SaeedZhiany
Copy link

SaeedZhiany commented Apr 14, 2020

@satya164

I'm facing this problem in RN 0.62.2 and react-navigation 5.x.x.

In my case, this only happens when the Fast refresh feature is enabled and I change some part of my code. it's probably a debug phase problem and should not happens in production, but it's very annoying because it makes the Fast refresh useless to development.

I also tried the link you mentioned, the result is the same

@gastondisacco
Copy link

Facing same issue over here. Tried all doc says related with initialization. (https://reactnavigation.org/docs/navigating-without-navigation-prop/#handling-initialization)

software version
iOS or Android iOS
@react-navigation/native 5.0.5
react-native 0.61.0
expo 3.18.6
node v12.16.1
npm or yarn 1.22.4

@superguineapig
Copy link

superguineapig commented May 5, 2020

Hi, I know this issue is closed, but I did some experiments, and it looks like there is different behavior between a class component and a function component that leads to async initialization of the navigation ref

I put together a snack (based on the official documentation) that demonstrates this. Swap the commented App component to see the difference in behavior.

https://snack.expo.io/H3O3jaNxi

I'm a bit surprised that there is a difference between useEffect and componentDidMount in this regard. The v5 docs only mention using the functional useEffect style, but as someone who is converting over from v4 and mostly class components, this is a bit of a 'gotcha'.

Hope this helps.

@narkai
Copy link

narkai commented May 12, 2020

Same here, what's suggested in the doc is not working.

https://reactnavigation.org/docs/navigating-without-navigation-prop/#handling-initialization

Sometimes the error occurs, sometimes not...

@gilbertl
Copy link

Encountered the same on RN 61.5. My terribly hacky workaround was to wrap navigate() in a setTimeout with 100 ms delay.

This works for me, although 0ms is enough.

@narkai
Copy link

narkai commented May 12, 2020

I don't know if this can help someone but I solved it by reversing the problem :

Instead of navigating-without-navigation-prop and handling-initialization, I made the navigation prop available to my component by nesting it in another Stack.Navigator.

No need for a RootNavigation object and the code is also more logical in a sense...

@Bardiamist
Copy link

// You can decide what to do if the app hasn't mounted
// You can ignore this, or add these actions to a queue you can call later

Why every app should handle it. Queue shold be created by react-navigation.
Also isn't clear lifecycle for me. When app can be unmounted? I thought that app can be unmounted only once one close.

@patrickreiner
Copy link

+1 on this, I followed what is says here:

https://reactnavigation.org/docs/navigating-without-navigation-prop/#handling-initialization

still getting the initialization error

@meshaabi
Copy link

meshaabi commented Sep 14, 2020

solved it like this, if it helps anyone

export const dispatch = action => {
  if (navigationRef.current?.dispatch) {
    setTimeout(() => navigationRef.current.dispatch(action));
    return true;
  } else {
    dispatchQueue.push(action);
    setTimeout(() => {
      dispatchQueue = dispatchQueue.filter(value => {
        return !dispatch(value);
      });
    });
    return false;
  }
};

@Anurag-Srivastav
Copy link

Doing the same with RN.5.. still getting the initialization error..
Followed what it says
https://reactnavigation.org/docs/navigating-without-navigation-prop/#handling-initialization
still getting the initialization error

@upngo
Copy link

upngo commented Dec 10, 2020

<NavigationContainer ref={navigationRef} onReady={() => { alert(navigationRef.current.dangerouslyGetState() === undefined)}>...</NavigationContainer> returns true

onReady is returning when we the navigationRef is set, but before it's been initialised

@gretzky
Copy link

gretzky commented Mar 10, 2021

This issue is still happening.

Repro: https://snack.expo.io/1TiQCzjM3

cc @satya164

@hsavit1
Copy link

hsavit1 commented Mar 29, 2021

issue still happens even if you're not using useLinking

@Alexddsilva
Copy link

Alexddsilva commented Apr 20, 2021

Still happens why is closed? this part of documentation is broken
https://reactnavigation.org/docs/navigating-without-navigation-prop/#handling-initialization

@hsavit1
Copy link

hsavit1 commented Apr 20, 2021

i think a key for this fix is to make sure that the navigation is "ready" . there's an onReady prop for the navigation container

@github-actions
Copy link

Hey! This issue is closed and isn't watched by the core team. You are welcome to discuss the issue with others in this thread, but if you think this issue is still valid and needs to be tracked, please open a new issue with a repro.

@chengqing97
Copy link

Hey I've got a workaround here!

It is basically set "isReady" variable to true only when the first screen inside the navigator is mounted.

This is a simplified version of my code when I am working with deep linking which I want to navigate to a screen immediately after the navigator is ready.

import React, { useEffect, useState } from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { LogBox } from "react-native";

const Stack = createStackNavigator();

const MainStack = () => {
  const [navigatorIsReady, setNavigatorIsReady] = useState(false);

  useEffect(() => {
    if (navigatorIsReady) RootNavigation.navigate("Screen2");
  }, [navigatorIsReady]);

  LogBox.ignoreLogs(["Non-serializable values were found in the navigation state"]);

  return (
    <Stack.Navigator>
      <Stack.Screen name="Screen1" component={Screen1} initialParams={{ setNavigatorIsReady }} />
      <Stack.Screen name="Screen2" component={Screen2} />
      <Stack.Screen name="Screen3" component={Screen3} />
    </Stack.Navigator>
  );
};

export default MainStack;

And then in Screen1:

const Screen1 = ({ route }) => {
  const setNavigatorIsReady = route.params.setNavigatorIsReady;

  useEffect(() => {
    setNavigatorIsReady(true);
  }, []);
  
  return (
    <View>
      <Text>This is screen 1</Text>
    </View>
  )
}

I'm passing setState as params and ignoring the warning because I'm not accessing the state somewhere else and I didn't use state persistence or React Navigation's deep link as stated in the Official Docs. But you can use React Context as well :)

@jojonarte
Copy link

Can confirm that this is still happening on the latest

@pollie80
Copy link

My error was that I was missing this ref: <NavigationContainer ref={navigationRef}>

@AtesDANIS
Copy link

Encountered the same on RN 61.5. My terribly hacky workaround was to wrap navigate() in a setTimeout with 100 ms delay.

Not even 1000ms was enough, wrote 2000ms and worked. very disturbing...
thanks

@lay-mand
Copy link

lay-mand commented Oct 18, 2021

I have a state var that is set to true when onReady is called, but I am still experiencing this error in production.

I tried the timeout and it doesn't seem to work in my instance.

My use case here is for navigating to a certain screen when handling notifications: the error seems to occur only when the app has not previously been loaded.

The workaround for me was to defer the navigation inside one of the navigator screens.

Hi. Did you solve your problem? Interested because of facing the same case

@mschaefer-gresham
Copy link

Having same issue and setTimeout is not working. Why is this issue closed?

@mtnt
Copy link

mtnt commented Mar 15, 2022

I placed ref.isReady() right into useEffect:

const navigationRef = useNavigationContainerRef();

useEffect(() => {
    console.log('DBG: useEffect', navigationRef.isReady());
  }, [navigationRef]);

  return (
    <SafeAreaProvider>
      <NavigationContainer ref={navigationRef}>
// ....

And it consoled false...

How to get a moment, when it is ready?

@mtnt
Copy link

mtnt commented Mar 15, 2022

@satya164 why the issue is still closed? there are a lot of reprodution repos

@oktaysenkan
Copy link

I created new library for handling navigation initialization

react-native-wait-navigation

@jzxchiang1
Copy link

I still see this after setting a state variable in NavigationContainer's onReady, and then calling navigationRef.current?.navigate only when that state variable becomes true in a useEffect.

Nothing seems to work (on iOS)

@azizmobarak
Copy link

azizmobarak commented Apr 27, 2022

I have the same issue , React Native 67 and Navigation 6.x

have just fixed it , this is an example

const navigationRef = useNavigationContainerRef();
 const yourRefName = useRef<any>(); // add some type

const onStateChanged = () => {
    yourRefName.current  = navigationRef.getCurrentRoute(); // use ref here to change value
  };

  const onNavigationReady = () => {
    routeNameRef.current = navigationRef.getCurrentRoute(); // initialise ref 
  };

  return (
    <NavigationContainer
      ref={navigationRef} // link navigation to the container
      onReady={onNavigationReady}
      onStateChange={onStateChanged}
    >
....
</NavigationContainer>

@sudipstha08
Copy link

Facing the same issue

@mondd-io
Copy link

mondd-io commented May 4, 2022

I had the same issue like a lot of commenters. Tried to navigate upon receiving notifications. Tried the NavigationContainer's ref using the docs https://reactnavigation.org/docs/navigating-without-navigation-prop#handling-initialization

The suggested createNavigationContainerRef "didn't work" I used useNavigationContainerRef instead, as @azizmobarak suggested. Now it works like it should. Not sure what's the actual bug here maybe they should just review their docs?

@react-navigation/native 6.0.8

@JoshWeiner
Copy link

Would either of you @albert-hajdu-mondd-io or @azizmobarak be able to provide some sort of reproduction as to how you implemented this change? Within the framework given in the react-navigation documentation I was unable to reproduce a successful solution with the information you provided.

@mondd-io
Copy link

mondd-io commented May 6, 2022

@JoshWeiner something like this:

export const App = () => {
  const navigationRef = useNavigationContainerRef()

  const navigate = (name: any, params: any) => {
    if (navigationRef.isReady()) {
      navigationRef.navigate(name, params)
    }
  }

  useEffect(() => {
    Notifications.events().registerNotificationOpened((notification: Notification, completion) => {
      navigate(...)
      completion()
    })
  }, [])

  return (
    <NavigationContainer ref={navigationRef}>
      ...
    </NavigationContainer>
  )
}

@YuriVini
Copy link

YuriVini commented May 25, 2022

For who is getting this error in a jest test. That's what I did...

const { getByTestId } = render(
        <NavigationContainer ref={navigationRef}>
          <ComponentHere {...props} />
        </NavigationContainer>
    );

const yourTextID = getByTestId('yourTextID');

setTimeout(() => {
      fireEvent.press(yourTextID);
}, 1000);

@mikhail-talkshoplive
Copy link

mikhail-talkshoplive commented Jul 28, 2022

why this issue closed? if app opened and user click universal link, navigationRef.isReady() - is always false, even after 10 second timeout
https://reactnavigation.org/docs/deep-linking/
"If the app was already open, the deep link needs to update the state to reflect the incoming link" - how to update if navigationRef.isReady() = false?

@oktaysenkan
Copy link

why this issue closed? if app opened and user click universal link, navigationRef.isReady() - is always false, even after 10 second timeout https://reactnavigation.org/docs/deep-linking/ "If the app was already open, the deep link needs to update the state to reflect the incoming link" - how to update if navigationRef.isReady() = false?

checkout this library

https://github.com/oktaysenkan/react-native-wait-navigation

@mtnt
Copy link

mtnt commented Jul 28, 2022

checkout this library

https://github.com/oktaysenkan/react-native-wait-navigation

@oktaysenkan Why you made the lib to fix an issue of another one? If you know how to fix, just make a PR =)

@mikhail-talkshoplive
Copy link

why this issue closed? if app opened and user click universal link, navigationRef.isReady() - is always false, even after 10 second timeout https://reactnavigation.org/docs/deep-linking/ "If the app was already open, the deep link needs to update the state to reflect the incoming link" - how to update if navigationRef.isReady() = false?

checkout this library

https://github.com/oktaysenkan/react-native-wait-navigation

thanks, your package solved my problem

@angmarb
Copy link

angmarb commented Nov 8, 2022

My team have experienced "The 'navigation' object hasn't been initialized yet" error inside onReady callback. The problem was with conditional rendering inside NavigationContainer, like:

<NavigationContainer>
  if (condition1) {
   return <StackNavigator1>;
  }
  if (condition2) {
   return <SomeScreen>;
  }
  if (condition3) {
   return <StackNavigator2>;
  }
</NavigationContainer>

rewriting it so every stack is stable with a navigation container solved the issue:

  if (condition1) {
   return 
     <NavigationContainer>
      <StackNavigator1> 
   </NavigationContainer>
  }
  if (condition2) {
   return <SomeScreen>;
  }
  if (condition3) {
   return 
     <NavigationContainer>
      <StackNavigator2> 
   </NavigationContainer>
  }

Hope that helps someone.

@NorbertSanpruch
Copy link

I am facing the same issue with deep links and push notifications. I've created a function that checks if the navigationRef is ready and returns a promise.

  const waitForNavigationToBeReady = () => {
    const checkIfReady = (resolve: (value: unknown) => void) => {
      if (navigationRef.isReady()) {
        resolve(true);
      }

      setTimeout(() => {
        checkIfReady(resolve);
      }, 25);
    };

    return new Promise(resolve => {
      checkIfReady(resolve);
    });
  };

It checks if navigation is ready each 25 ms. Then in my handleDeepLink function I do

  const handleDeepLink = async () => {
    await waitForNavigationToBeReady();
    navigationRef.navigate();
  };

Hope it helps someone.

@2sem
Copy link

2sem commented Apr 26, 2023

I met this problem when I modify font size in the setting app.
So I solved it by calling navigation dispatch in a timeout.

setTimeout(() => {
      NavigationService.replace({
        routeName: targetScreen,
        params: {
          ...
        },
      })
    }, 0)

@2sem
Copy link

2sem commented May 2, 2023

This is not error, I can't catch it.
This problem is occurred when I modify font size in the settings app on android device.

This is so weird, I tried to call on 'focus' event in the first screen.
However problem was not disappeared.

So I had to resolve with setTimeout.

@vincentmegia
Copy link

vincentmegia commented Oct 5, 2023

For Jest what's weird this worked for me, normally we don't need instance of Stack.Navigator

<NavigationContainer ref={navigationRef}> <Provider store={store}> <Login /> </Provider> <Stack.Navigator> <Stack.Screen name='someScreen' component={SomeScreen} /> </Stack.Navigator> </NavigationContainer>

@m-korkut
Copy link

I still get the error.
isReady() function returns false in all cases.

@DavidKnight-Bluescape
Copy link

My error was that I was missing this ref: <NavigationContainer ref={navigationRef}>

Thank you - this was not explicitly mentioned in the docs, and is a crucial step. Maybe its obvious to folks who have been using this library for a while, but was not for me.

@HugoBounoua
Copy link

SOLUTION:
Your initialization is correct:

<NavigationContext.Provider value={isNavigationContextReady ? navigationRef.current : null}>
     <NavigationContainer ref={navigationRef} onReady={() => setIsNavigationContextReady(true)}>
         ....

But your usage is not.
You are referencing the navigation like this and it's good:

const appNavigation: NavigationContainerRef<AppNavigationScreens> | null = useAppNavigation() as NavigationContainerRef<AppNavigationScreens> | null;

And you use it automatically without a user event (which normally takes a few seconds..) before the navigation is ready.
But the problem is that the navigation might not be ready when you USE it.
What you want to be doing is waiting for the navigation to actually tell you it's ready, like so:

    {
        if(appNavigation && appNavigation.isReady())
            appNavigation.navigate("IT_IS_SAFE_TO_NAVIGATE");
        else
           console.log(`AppNavigation is not ready yet...`);
    }, [appNavigation?.isReady()]);
    

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests