can't find variable: user.I am using firebase auth and the latest SDK, expo SDK 42, react navigation 6.x.x

Viewed 310
import React, { useEffect } from "react";
import { StyleSheet, Text, View } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import LoginScreen from "./screens/LoginScreen";
import SignUpScreen from "./screens/SignUpScreen";
import WelcomeScreen from "./screens/WelcomeScreen";
import OnBoard from "./screens/Onboard";
import GetStarted from "./screens/GetStarted";
import { auth } from "./firebase";

const Stack = createNativeStackNavigator();

export default function App() {
  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((user) => {
      console.log(user);
      return user;
    });
    return unsubscribe;
  }, []);

  return (
    <NavigationContainer>
      <Stack.Navigator>
        {user ? (
          <>
            <Stack.Screen
              options={{ headerShown: false }}
              name="OnBoard"
              component={OnBoard}
            />
            <Stack.Screen
              options={{ headerShown: false }}
              name="SignUp"
              component={SignUpScreen}
            />
            <Stack.Screen
              options={{ headerShown: false }}
              name="Login"
              component={LoginScreen}
            />
          </>
        ) : (
          <Stack.Screen
            options={{ headerShown: false }}
            name="Welcome"
            component={WelcomeScreen}
          />
        )}
      </Stack.Navigator>
    </NavigationContainer>
  );
}

can't find variable :user, I can't understand also I am new to react-native and react-navigation. I tried returning user but unlined or something.

tried

const isLoggedIn = user;
console.log(isLoggedIn)

It just logs undefined. Anyone can help me with it?

I am using firebase auth and the latest SDK, expo SDK 42, react navigation 6.x.x Using condition rendering for the to hide the onBoarding, logIn and signUp screen when the app loads and the user is authenticated so he directly does to welcomeScreen

Link to the expo snack. Run it in your device not on the web. https://snack.expo.dev/@bishalsaha/a638cf

2 Answers

Hint: You might want regenerate your api key as you made it public in your comment!

Assuming your authentification works fine and your log in useEffect isn't undefined, your app might work with fixing the way you handling your user variable:

export default function App() {
  const [isLoggedIn, setIsLoggedIn] = React.useState(false);
  const [user, setUser] = React.useState();
  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((receivedUser) => {
      console.log(receivedUser);
      setUser(receivedUser);
      setIsLoggedIn(true);
    });
    unsubscribe();
  }, []);

  // Check your logs
  console.log(user);
  console.log(isLoggedIn);

  return (
    <NavigationContainer>
      <Stack.Navigator>
        {user ? (
          <>
            <Stack.Screen
              options={{ headerShown: false }}
              name="OnBoard"
              component={OnBoard}
            />
            <Stack.Screen
              options={{ headerShown: false }}
              name="SignUp"
              component={SignUpScreen}
            />
            <Stack.Screen
              options={{ headerShown: false }}
              name="Login"
              component={LoginScreen}
            />
          </>
        ) : (
          <Stack.Screen
            options={{ headerShown: false }}
            name="Welcome"
            component={WelcomeScreen}
          />
        )}
      </Stack.Navigator>
    </NavigationContainer>
  );
}

EDIT: Following your question about holding the state after reload:

As mentioned in the React Native Docs storing a state is provided by something called AsyncStorage and Secure Storage. Async Storage goes for everything that goes for something like a graphql or persisted statemanagement stuff.

As your users email and password belong to the sensitve data category I highly recommend going with expo-secure-storage. If you don't wish to go with a refactoring I would alter the handleLogin function in your provived example:

import * as SecureStore from 'expo-secure-store';

// [your components code]

 const handleLogin = () => {
    let data = await SecureStore.getItemAsync(userCredsKey);
    userCreds = userCreds ? JSON.parse(data)
    if (!userCreds) {
      userCreds = { email: email, password: password };
    }
    auth
      .signInWithEmailAndPassword(userCreds.email, userCreds.password)
      .then((userCredentials) => {
        const user = userCredentials.user;
        console.log("Logged in with:", user.email);
        //login successfull
        await SecureStorage.setItemAsync(userCredsKey, JSON.stringify(userCreds));
      })
      .catch((error) => alert(error.message));
  };

Note: The above code only shows the idea of how you can use secure storage and sign in your user after reloading the app. You might want go another path here or even better decoupling the logic from your components in an dedicated service file :-)

Use local storage

I was facing the same issue, I used local storage to save the user data, and upon refreshing or reloading the app will get data from local storage. This is how I approached the issue on the web.

// useState
    const [currentUser, setCurrentUser] = useState(() => {
      const data = localStorage.getItem("currentUser"); // Get data from local storage when the app is reloaded or refreshed. If there is some data in local storage the app will use that.
      return data ? JSON.parse(data) : {};
    });



// useEffect
seEffect(() => {
  const unsubscribe = auth.onAuthStateChanged(user => {
    localStorage.setItem("currentUser", JSON.stringify(user)); // Saving user to your app local storage
    setCurrentUser(user);
  })
  return unsubscribe
}, [])
Related