Jwan622
Jwan622

Reputation: 11659

React native wait until user is logged in before navigating screens

I have a function that retrieves a token from SecureStore in react-native

export const isUserLoggedIn = async () =>{
  return await SecureStore.getItemAsync('jwtToken') ? true : false
}

This is my navigator:

function RootNavigator() {
  const [isLoggedIn, setIsLoggedIn] = useState(false)

  console.log("isUserLoggedIn()", isUserLoggedIn());
  (async () => {
    const someBoolean =  await isUserLoggedIn()
    console.log("inside then")
    setIsLoggedIn(someBoolean)

    return (
      <Stack.Navigator screenOptions={{ headerShown: false }}>
        {isLoggedIn || <Stack.Screen name="Root" component={WelcomeScreen} />}
        {isLoggedIn && <Stack.Screen name="InvestorProfileQuiz" component={InvestorProfileQuizScreen} />}
        {isLoggedIn || <Stack.Screen name="AppTour" component={AppTourScreen} />}
        {isLoggedIn || <Stack.Screen name="Login" component={LoginScreen} />}
        {isLoggedIn || <Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />}
      </Stack.Navigator>
    );
  })()
  console.log("LOGGED IN STATE:", isLoggedIn)

The issue is that the LOGGED_IN_STATE is logged before the inside then console.log which means the code isn't blocking and waiting for the isUserLoggedIn() to resolve. isUserLoggedIn() returns a promise because it's an async await function, but do I wait for it to resolve before rendering the Stack Navigator? I in short want a logged in user to have access to certain screens and not others. What am I doing wrong?

Upvotes: 2

Views: 1274

Answers (1)

Jack Vial
Jack Vial

Reputation: 2474

I usually handle logged in state with something like this:

function RootNavigator() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  // Passing an empty array as second argument
  // makes useEffect behave like componentDidMount
  useEffect(() => {
    
    // Wrap logic in the async init function
    // since the useEffect callback can't be async
    async function init() {
      const someBoolean = await isUserLoggedIn();
      setIsLoggedIn(someBoolean);
    }
    init();
  }, []);

  // Return null or your logged out screen component here.
  if (!isLoggedIn) {
    return null;
  }

  return (
    <Stack.Navigator screenOptions={{headerShown: false}}>
      <Stack.Screen name="Root" component={WelcomeScreen} />}
      <Stack.Screen
        name="InvestorProfileQuiz"
        component={InvestorProfileQuizScreen}
      />
      <Stack.Screen name="AppTour" component={AppTourScreen} />
      <Stack.Screen name="Login" component={LoginScreen} />(
      <Stack.Screen
        name="NotFound"
        component={NotFoundScreen}
        options={{title: 'Oops!'}}
      />
    </Stack.Navigator>
  );
}

In your code console.log("LOGGED IN STATE:", isLoggedIn) does not wait because the async await is incapsulated in the IIFE (https://developer.mozilla.org/en-US/docs/Glossary/IIFE) function scope.

Upvotes: 1

Related Questions