最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React native navigation v6 authentication flow - Stack Overflow

programmeradmin0浏览0评论

I have an app in which I login/register and can signout/logout, I'm using react navigation v6 for the same, and I'm able to login but when I logout it doesn't log me out immediately as it should, I will have to hot restart the app, & then I'm already logged out, it just doesn't log me out without hot restarting, also, while logging out, I get an error/warning:

error:

The action 'NAVIGATE' with payload {"name":"Login"} was not handled by any navigator.
Do you have a screen named 'Login'?
If you're trying to navigate to a screen in a nested navigator, see .
This is a development-only warning and won't be shown in production.

Below is the code I'm using:

Context file:

const initialState = {
  user: null,
  loading: false,
};

const UserContext = createContext(initialState);

export const UserProvider = ({children}) => {
  const [globalState, dispatch] = useReducer(UserReducer, initialState);

  return (
    <UserContext.Provider value={{
      user: globalState.user,
      loading: globalState.loading,
      dispatch,
    }} >
      {children}
    </UserContext.Provider>
  );
};

export default function() {
  return useContext(UserContext);
}

Navigation Screen:

const Navigation = () => {
  const {user, dispatch, loading} = useAuth();
  let navigationRef;

  useEffect(() => {
    setTimeout(() => {
      navigationRef = createNavigationContainerRef(); // To avoid getting error: navigator is undefined while the ponent is mounting...
    }, 500);
    checkUserLoggedInStatus(dispatch, navigationRef);
  }, [dispatch]);

  return loading ? (
    <LoadingScreen />
  ) : (
    <Stack.Navigator screenOptions={{headerShown: false}}>
      {!user ? (
        <Stack.Group>
          <Stack.Screen name="Login" ponent={LoginScreen} />
          <Stack.Screen name="Register" ponent={RegisterScreen} />
        </Stack.Group>
      ) : (
        <Stack.Group>
          <Stack.Screen name="Home" ponent={HomeScreen} />
          <Stack.Screen name="Settings" ponent={SettingsScreen} />
        </Stack.Group>
      )}
    </Stack.Navigator>
  );
};

checkUserLoggedInStatus, login & logout utility function:

export const login = (otp, userId, dispatch) => {
  dispatch(SET_LOADING(true));
  fetch(`${API_URL}/auth/login/`, {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({...}),
  })
    .then(response => response.json())
    .then(data => {
      if (data.error) {
        console.log('[ERROR] While trying to login: ', data.error);
        dispatch(SET_LOADING(false));
      }
      if (data.type === 'success') {
        AsyncStorage.setItem('token', data.data.token)
          .then(response => console.log(response))
          .catch(err => console.log(err));

        const userDetails = data.data.user;
        dispatch(SET_USER_DETAILS(userDetails));
        dispatch(SET_LOADING(false));
      }
    })
    .catch(error => {
      console.log('[ERROR] While logging in: ' + error.message);
      dispatch(SET_LOADING(false));
    });
};

export const checkUserLoggedInStatus = (dispatch, navigator) => {
  dispatch(SET_LOADING(true));
  AsyncStorage.getItem('token')
    .then(token => {
      if (token) {
        fetch(`${API_URL}/user/`, {
          method: 'GET',
          headers: {...},
        })
          .then(response => response.json())
          .then(data => {
            if (data.type === 'success') {
              const details = data.data.user;
              dispatch(SET_USER_DETAILS(details));
              dispatch(SET_LOADING(false));
            }
            if (data.error) {
              console.log('[INFO] Your token expired.');
              if (navigator.isReady()) {
                navigator.navigate('Login');
              }
            }
          })
          .catch(error => {
            console.log('[ERROR] While fetching profile: ' + error.message);
            dispatch(SET_LOADING(false));
          });
      } else {
        dispatch(SET_LOADING(false));
      }
    })
    .catch(error => {
      console.log('[ERROR] While fetching token: ' + error.message);
      dispatch(SET_LOADING(false));
    });
};

export const logout = async (dispatch, navigator) => {
  dispatch(SET_LOADING(true));
  await AsyncStorage.removeItem('token');
  navigator.navigate('Login');
  dispatch(SET_LOADING(false));
};

// HERE I LOGOUT FROM MY SETTINGS SCREEN (WHEN I'M AUTHENTICATED).

As you can see the error (first few lines of code), I cannot correctly navigate/logout from my app. Any help would be really appreciated!

I have an app in which I login/register and can signout/logout, I'm using react navigation v6 for the same, and I'm able to login but when I logout it doesn't log me out immediately as it should, I will have to hot restart the app, & then I'm already logged out, it just doesn't log me out without hot restarting, also, while logging out, I get an error/warning:

error:

The action 'NAVIGATE' with payload {"name":"Login"} was not handled by any navigator.
Do you have a screen named 'Login'?
If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
This is a development-only warning and won't be shown in production.

Below is the code I'm using:

Context file:

const initialState = {
  user: null,
  loading: false,
};

const UserContext = createContext(initialState);

export const UserProvider = ({children}) => {
  const [globalState, dispatch] = useReducer(UserReducer, initialState);

  return (
    <UserContext.Provider value={{
      user: globalState.user,
      loading: globalState.loading,
      dispatch,
    }} >
      {children}
    </UserContext.Provider>
  );
};

export default function() {
  return useContext(UserContext);
}

Navigation Screen:

const Navigation = () => {
  const {user, dispatch, loading} = useAuth();
  let navigationRef;

  useEffect(() => {
    setTimeout(() => {
      navigationRef = createNavigationContainerRef(); // To avoid getting error: navigator is undefined while the ponent is mounting...
    }, 500);
    checkUserLoggedInStatus(dispatch, navigationRef);
  }, [dispatch]);

  return loading ? (
    <LoadingScreen />
  ) : (
    <Stack.Navigator screenOptions={{headerShown: false}}>
      {!user ? (
        <Stack.Group>
          <Stack.Screen name="Login" ponent={LoginScreen} />
          <Stack.Screen name="Register" ponent={RegisterScreen} />
        </Stack.Group>
      ) : (
        <Stack.Group>
          <Stack.Screen name="Home" ponent={HomeScreen} />
          <Stack.Screen name="Settings" ponent={SettingsScreen} />
        </Stack.Group>
      )}
    </Stack.Navigator>
  );
};

checkUserLoggedInStatus, login & logout utility function:

export const login = (otp, userId, dispatch) => {
  dispatch(SET_LOADING(true));
  fetch(`${API_URL}/auth/login/`, {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({...}),
  })
    .then(response => response.json())
    .then(data => {
      if (data.error) {
        console.log('[ERROR] While trying to login: ', data.error);
        dispatch(SET_LOADING(false));
      }
      if (data.type === 'success') {
        AsyncStorage.setItem('token', data.data.token)
          .then(response => console.log(response))
          .catch(err => console.log(err));

        const userDetails = data.data.user;
        dispatch(SET_USER_DETAILS(userDetails));
        dispatch(SET_LOADING(false));
      }
    })
    .catch(error => {
      console.log('[ERROR] While logging in: ' + error.message);
      dispatch(SET_LOADING(false));
    });
};

export const checkUserLoggedInStatus = (dispatch, navigator) => {
  dispatch(SET_LOADING(true));
  AsyncStorage.getItem('token')
    .then(token => {
      if (token) {
        fetch(`${API_URL}/user/`, {
          method: 'GET',
          headers: {...},
        })
          .then(response => response.json())
          .then(data => {
            if (data.type === 'success') {
              const details = data.data.user;
              dispatch(SET_USER_DETAILS(details));
              dispatch(SET_LOADING(false));
            }
            if (data.error) {
              console.log('[INFO] Your token expired.');
              if (navigator.isReady()) {
                navigator.navigate('Login');
              }
            }
          })
          .catch(error => {
            console.log('[ERROR] While fetching profile: ' + error.message);
            dispatch(SET_LOADING(false));
          });
      } else {
        dispatch(SET_LOADING(false));
      }
    })
    .catch(error => {
      console.log('[ERROR] While fetching token: ' + error.message);
      dispatch(SET_LOADING(false));
    });
};

export const logout = async (dispatch, navigator) => {
  dispatch(SET_LOADING(true));
  await AsyncStorage.removeItem('token');
  navigator.navigate('Login');
  dispatch(SET_LOADING(false));
};

// HERE I LOGOUT FROM MY SETTINGS SCREEN (WHEN I'M AUTHENTICATED).

As you can see the error (first few lines of code), I cannot correctly navigate/logout from my app. Any help would be really appreciated!

Share Improve this question asked Jan 4, 2022 at 16:10 dev1cedev1ce 1,7475 gold badges29 silver badges57 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 8

Theres two things to adjust in your logout action by the looks of things.

  1. you are removing the token from AsyncStorage, but you still have a user object set in your useAuth hook which is what conditionally renders the stack group containinig login/register, or the stack group with home/settings:
{!user ? (
        <Stack.Group>
          <Stack.Screen name="Login" ponent={LoginScreen} />
          <Stack.Screen name="Register" ponent={RegisterScreen} />
        </Stack.Group>
      ) : (
        <Stack.Group>
          <Stack.Screen name="Home" ponent={HomeScreen} />
          <Stack.Screen name="Settings" ponent={SettingsScreen} />
        </Stack.Group>
      )}

so the user is not falsy and will still render the home/settings hence you aren't navigating back to the login. Dispatch an action to set that back to null and you'll automatically navigate back to login.

  1. The typical logout flow for use when you are using react-navigation means that when you perform the logout action you don't actually need to do the navigator.navigate('Login') because the default route for that stack will be back to the login (just set this in the navigator), as the screen isn't currently rendered due to the first point I mentioned above (conditionally rendering them, the screen literally doesn't exist at the point you're navigating) so you can safely remove this line.
发布评论

评论列表(0)

  1. 暂无评论