Home > Software design >  React Native - Authentication - trigger value to change Auth & UnAuth Stack Navigators
React Native - Authentication - trigger value to change Auth & UnAuth Stack Navigators

Time:12-29

Here my App.js

import React, { useEffect } from "react";
import { NavigationContainer } from "@react-navigation/native";

import AuthStore from "./src/stores/AuthStore";
import AuthStackNavigator from "./src/navigation/AuthStackNavigator";
import UnAuthStackNavigator from "./src/navigation/UnAuthStackNavigator";

const App = () => {
  useEffect(() => {
    console.log("APP JS", AuthStore.userAuthenticated);
  }, [AuthStore.userAuthenticated]);

  return <NavigationContainer>
    {AuthStore.userAuthenticated ? <AuthStackNavigator /> : <UnAuthStackNavigator />}
    </NavigationContainer>;
};

export default App;

The AuthStore value of userAuthenticated is computed and updated on auto login or login.

Here AuthStore.js

import { userLogin, userRegister } from "../api/AuthAgent";
import { clearStorage, retrieveUserSession, storeUserSession } from "../utils/EncryptedStorage";
import { Alert } from "react-native";
import { computed, makeObservable, observable } from "mobx";
import { setBearerToken } from "../config/HttpClient";

class AuthStore {
  user = {};
  token = undefined;
  refreshToken = undefined;
  decodedToken = undefined;
  
  constructor() {
    makeObservable(this, {
      token: observable,
      refreshToken: observable,
      user: observable,
      decodedToken: observable,
      userAuthenticated: computed,
    });
    this.autoLogin();
  }

  async doLogin(body) {
    const resp = await userLogin(body);
    console.log("AuthStore > userLogin > resp => ", resp);

    if (resp.success) {
      this.decodedToken = await this.getDecodedToken(resp.token);
      this.setUserData(resp);
      storeUserSession(resp);
    } else {
      Alert.alert(
        "Wrong credentials!",
        "Please, make sure that your email & password are correct",
      );
    }
  }

  async autoLogin() {
    const user = await retrieveUserSession();
    if (user) {
      this.setUserData(user);
    }
  }

  setUserData(data) {
    this.user = data;
    this.token = data.token;
    setBearerToken(data.token);
  }

  get userAuthenticated() {
    console.log('AuthStore > MOBX - COMPUTED userAuthenticated', this.user);
    if (this.token) {
      return true;
    } else return false;
  }

  async logout() {
    await clearStorage();
    this.user = undefined;
    this.token = undefined;
    this.refreshToken = undefined;
    this.decodedToken = undefined;
  }

}

export default new AuthStore();

The main problem is that the AuthStore.userAuthenticated value even when it changes on AuthStore it does not triggered by useEffect of the App.js. So, when I log in or log out I have to reload the App to trigger the useEffect hook and then the navigators are only updated.

CodePudding user response:

You can use useMemo hook to achive this.

const App = () => {
const [userToken, setUserToken] = useState("")  


const authContext: any = useMemo(() => {
        return {
          signIn: (data: any) => {
            AsyncStorage.setValue("token", data.accessToken);
            setUserToken(data.accessToken);
          },
          signOut: () => {
            setUserToken("");
            AsyncStorage.setValue("token", "");
          },
        };
      }, []);


 return ( 
    <AuthContext.Provider value={authContext}>
              {userToken.length ? (
                <UnAuthStackNavigator />
              ) : (
                <AuthStackNavigator />
              )}
            )
    </AuthContext.Provider>
 )
}

AuthContext.ts

import React from "react";
export const AuthContext: any = React.createContext({
  signIn: (res: any) => {},
  signOut: () => {},
});

Now you can use this functions in any files like this:

    export const SignIn = () => {
       const { signIn } = useContext(AuthContext);
           return (
             <Button onPress={() => {signIn()}}  />
           )
    }

CodePudding user response:

If your primary purpose is to navigate in and out of stack if authentication is available or not then asynstorage is the best option you have to first store token.

    const storeToken = async (value) => {
  try {
    await AsynStorage.setItem("userAuthenticated", JSON.stringify(value));
  } catch (error) {
    console.log(error);
  }
};

("userAuthenticated" is the key where we get the value )

Now go to the screen where you want this token to run turnery condition

const [token, setToken] = useState();

const getToken = async () => {
  try {
    const userData = JSON.parse(await AsynStorage.getItem("userAuthenticated"))
    setToken(userData)
  } catch (error) {
   console.log(error); 
  }
};

Now use the token in the state then run the condition:

  {token? <AuthStackNavigator /> : <UnAuthStackNavigator />}
    or 
     {token != null? <AuthStackNavigator /> : <UnAuthStackNavigator />}

  • Related