首页 > 解决方案 > Expo / ReactNative - React Navigation - 条件认证流程

问题描述

我尝试使用条件身份验证流程。

代码:

return (
    
    <ApolloProvider client={client}>
      
    <NavigationContainer>
      
      
    <AuthProvider>
   
      <Stack.Navigator>
      
    {userToken ? 
    // User is signed in, show Home Screen
      
    <Stack.Screen name="Home" component={HomeScreen} />

    :
      // No token found, user isn't signed in, show the signin screen
     
      <Stack.Screen
        name="SignIn"
        component={SignInScreen}
        options={{
          headerShown: false,
        }}
      />
      
       
     
      }
      
  </Stack.Navigator>
  
  </AuthProvider>
      </NavigationContainer>
    
      </ApolloProvider>
      
      
  );
}

在两个屏幕(主页、登录)上,我都显示了 userToken 状态,以便轻松查看是否发生了变化。

当我登录时,userToken 从 null 更改为令牌字符串,但屏幕卡在 SignInScreen 上。当我注销时,userToken 从令牌字符串变为 null,但屏幕始终相同。

我不明白为什么不工作。阅读很多,检查示例,对我来说到处都是一样的。找不到任何可能导致它不起作用的差异。

有人可以帮助我吗?

亲切的问候,奥斯卡

编辑:我从哪里得到 userToken

/// Auth.tsx

import * as React from 'react';
import { getToken, setToken, removeToken } from './utils';

interface AuthState {
  userToken: string | undefined | null;
  status: 'idle' | 'signOut' | 'signIn';
}
type AuthAction = { type: 'SIGN_IN'; token: string } | { type: 'SIGN_OUT' };

type AuthPayload = string;

interface AuthContextActions {
  signIn: (data: AuthPayload) => void;
  signOut: () => void;
}

interface AuthContextType extends AuthState, AuthContextActions {}
const AuthContext = React.createContext<AuthContextType>({
  status: 'idle',
  userToken: null,
  signIn: () => {},
  signOut: () => {},
});

// In case you want to use Auth functions outside React tree
export const AuthRef = React.createRef<AuthContextActions>();

export const useAuth = (): AuthContextType => {
  const context = React.useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be inside an AuthProvider with a value');
  }
  return context;
};

export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
  const [state, dispatch] = React.useReducer(AuthReducer, {
    status: 'idle',
    userToken: null,
  });

  React.useEffect(() => {
    const initState = async () => {
      try {
        const userToken = await getToken();
        if (userToken !== null) {
          dispatch({ type: 'SIGN_IN', token: userToken });
        } else {
          dispatch({ type: 'SIGN_OUT' });
        }
      } catch (e) {
        console.log('initState error '+e)
      }
    };

    initState();
  }, []);

  React.useImperativeHandle(AuthRef, () => authActions);

  const authActions: AuthContextActions = React.useMemo(
    () => ({
      signIn: async (token: string) => {
        dispatch({ type: 'SIGN_IN', token });
        await setToken(token);
      },
      signOut: async () => {
        await removeToken(); // TODO: use Vars
        dispatch({ type: 'SIGN_OUT' });
      },
    }),
    []
  );

  return (
    // <AuthContext.Provider value={{ ...state, ...authActions }}>
    <AuthContext.Provider value={{ ...state, ...authActions }}>
      {children}
    </AuthContext.Provider>
  );
};

const AuthReducer = (prevState: AuthState, action: AuthAction): AuthState => {
  switch (action.type) {
    case 'SIGN_IN':
      return {
        ...prevState,
        status: 'signIn',
        userToken: action.token,
      };
    case 'SIGN_OUT':
      return {
        ...prevState,
        status: 'signOut',
        userToken: null,
      };
  }
};

标签: react-nativeauthenticationexpoauthorizationreact-navigation

解决方案


此外,您的 useEffect 间接依赖于减速器上下文中的“userToken”。[]虽然它得到了一个迂回的方式(等待getToken()),但由于您的空(ie )依赖块,它不会在初始组件加载后再次检查,即:

React.useEffect(() => {
    const initState = async ....
    initState();
  }, []); 

考虑将最后一行更改为对您的 reducer 的 usertoken 状态的引用,该状态发生变化,因此它会反应性地更新自身或具有类似效果的东西。


推荐阅读