【问题标题】:React native navigation v6 authentication flowReact 本机导航 v6 身份验证流程
【发布时间】:2023-04-02 13:29:01
【问题描述】:

我有一个应用程序,我可以在其中登录/注册并且可以注销/注销,我正在使用react navigation v6,我可以登录,但是当我注销时它不会立即将我注销为它应该,我将不得不hot restart该应用程序,然后我已经注销,它只是不会在没有热重启的情况下注销我,而且,在注销时,我收到一个错误/警告:

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.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
This is a development-only warning and won't be shown in production.

下面是我正在使用的代码:

上下文文件:

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);
}

导航屏幕:

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

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

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

checkUserLoggedInStatus, login & logout 实用函数:

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).

正如您所看到的错误(前几行代码),我无法正确导航/退出我的应用程序。任何帮助将不胜感激!

【问题讨论】:

    标签: javascript reactjs react-native react-navigation


    【解决方案1】:

    从外观上看,您的注销操作有两点需要调整。

    1. 您正在从 AsyncStorage 中删除令牌,但您仍然在 useAuth 挂钩中设置了一个用户对象,该对象有条件地呈现包含登录/注册的堆栈组或具有主页/设置的堆栈组:
    {!user ? (
            <Stack.Group>
              <Stack.Screen name="Login" component={LoginScreen} />
              <Stack.Screen name="Register" component={RegisterScreen} />
            </Stack.Group>
          ) : (
            <Stack.Group>
              <Stack.Screen name="Home" component={HomeScreen} />
              <Stack.Screen name="Settings" component={SettingsScreen} />
            </Stack.Group>
          )}
    

    所以用户不是虚假的,并且仍然会呈现主页/设置,因此您不会导航回登录。调度一个操作将其设置回 null,您将自动导航回登录。

    1. 使用 react-navigation 时使用的典型注销流程意味着,当您执行注销操作时,您实际上不需要执行 navigator.navigate('Login'),因为该堆栈的默认路由将返回登录 (只需在导航器中设置它),由于我上面提到的第一点,当前没有渲染屏幕(有条件地渲染它们,屏幕在您导航的点实际上不存在)所以你可以安全地删除它行。

    【讨论】:

    • 是的,我刚刚意识到!非常感谢!
    猜你喜欢
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-04
    • 2021-02-23
    • 2020-08-26
    • 2020-06-02
    • 1970-01-01
    相关资源
    最近更新 更多