react-native - 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,
};
}
};
解决方案
此外,您的 useEffect 间接依赖于减速器上下文中的“userToken”。[]
虽然它得到了一个迂回的方式(等待getToken()),但由于您的空(ie )依赖块,它不会在初始组件加载后再次检查,即:
React.useEffect(() => {
const initState = async ....
initState();
}, []);
考虑将最后一行更改为对您的 reducer 的 usertoken 状态的引用,该状态发生变化,因此它会反应性地更新自身或具有类似效果的东西。
推荐阅读
- redirect - 重定向到根目录以获取 HAproxy 上的特定 url 路径
- solr - 从 5.x 升级后,无法使用 curl 删除 solr 7.7.x 中的条目
- react-native - 如何在 react-native-router-flux 中更改标题标题
- html - 可嵌入的第 3 方网络工具安全防止窃取密钥
- php - 如果 PHP 中出现任何字符,我如何验证 Ymd 格式的日期并检查每个值是否有效?
- git - 提交历史仅在一天内出现
- excel - EXCEL;如何列出多个范围内的数字
- javascript - 是否可以在 SVG 中的字符串(句子或单词)中找到字符宽度
- visual-studio - 无法解析对“项目”引用的“包”的引用
- excel - 如何根据多个条件将单元格从一个工作簿复制到另一个工作簿