【问题标题】:Expo / ReactNative - React Navigation - Conditional Auth FlowExpo / ReactNative - React Navigation - 条件认证流程
【发布时间】:2021-09-09 10:02:53
【问题描述】:

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

代码:

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 上。当我 SignOut 时,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,
      };
  }
};

【问题讨论】:

  • 您是否使用 const [token, setToken] = useState() 设置登录令牌?
  • @Amr 不,userToken 来自上下文。我在主帖中添加了代码

标签: react-native authentication expo authorization react-navigation


【解决方案1】:

尝试使用一个NavigationContainer 用于签名,一个NavigationContainer 用于未签名

看这个例子:https://github.com/akinncar/expo-star-wars/blob/master/src/routes.tsx

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-23
      • 1970-01-01
      • 2021-12-10
      • 2019-07-02
      • 1970-01-01
      • 2021-10-09
      • 2023-04-02
      • 2019-05-31
      相关资源
      最近更新 更多