【发布时间】: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