【发布时间】:2020-04-17 15:20:14
【问题描述】:
我在react-navigation auth flow guide 和FeathersJS react-native client 之后设置了一个基本的身份验证系统。
这是我的主要index.tsx 文件:
import 'react-native-gesture-handler';
import React, {
useReducer, useEffect, useMemo, ReactElement,
} from 'react';
import { Platform, StatusBar } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { AppLoading } from 'expo';
import { useFonts } from '@use-expo/font';
import SplashScreen from './screens/SplashScreen';
import { AuthContext } from './contexts';
import { client } from './utils';
import DrawerNavigator from './navigation/DrawerNavigator';
import LogonStackNavigator from './navigation/LogonStackNavigator';
interface State {
isLoading: boolean;
isSignOut: boolean;
userToken: string|null;
}
const App = (): ReactElement => {
/* eslint-disable global-require */
const [fontsLoaded] = useFonts({
'Lato-Regular': require('../assets/fonts/Lato-Regular.ttf'),
'Lato-Bold': require('../assets/fonts/Lato-Bold.ttf'),
'Poppins-Light': require('../assets/fonts/Poppins-Light.ttf'),
'Poppins-Bold': require('../assets/fonts/Poppins-Bold.ttf'),
});
/* eslint-enable global-require */
const [state, dispatch] = useReducer(
(prevState: State, action): State => {
switch (action.type) {
case 'RESTORE_TOKEN':
return {
...prevState,
userToken: action.token,
isLoading: false,
};
case 'SIGN_IN':
return {
...prevState,
isSignOut: false,
userToken: action.token,
};
case 'SIGN_OUT':
return {
...prevState,
isSignOut: true,
userToken: null,
};
default:
return prevState;
}
},
{
isLoading: true,
isSignOut: false,
userToken: null,
},
);
useEffect(() => {
const bootstrapAsync = async (): Promise<void> => {
let userToken;
try {
const auth = await client.reAuthenticate();
console.log('reAuthenticate:', auth);
userToken = auth.accessToken;
} catch (e) {
// eslint-disable-next-line no-console
console.log('reAuthenticate failure:', e);
}
dispatch({
type: 'RESTORE_TOKEN',
token: userToken,
});
};
bootstrapAsync();
}, []);
const authContext = useMemo(
() => ({
signIn: async (data) => {
// In a production app, we need to send some data (usually username, password) to server and get a token
// We will also need to handle errors if sign in failed
// After getting token, we need to persist the token using `AsyncStorage`
// In the example, we'll use a dummy token
// eslint-disable-next-line no-console
console.log('signIn', data);
try {
const auth = await client.authenticate({
strategy: 'local',
...data,
});
console.log(auth);
dispatch({
type: 'SIGN_IN',
token: 'dummy-auth-token',
});
} catch (e) {
console.log('signIn failure:', e);
}
},
signOut: async () => {
try {
await client.logout();
dispatch({ type: 'SIGN_OUT' });
} catch (e) {
console.log('signOut failure:', e);
}
},
signUp: async (data) => {
// In a production app, we need to send user data to server and get a token
// We will also need to handle errors if sign up failed
// After getting token, we need to persist the token using `AsyncStorage`
// In the example, we'll use a dummy token
// eslint-disable-next-line no-console
console.log('signUp', data);
dispatch({
type: 'SIGN_IN',
token: 'dummy-auth-token',
});
},
}),
[],
);
if (!fontsLoaded) {
return <AppLoading />;
}
if (state.isLoading) {
return <SplashScreen />;
}
return (
<AuthContext.Provider value={authContext}>
{Platform.OS === 'ios' && (
<StatusBar barStyle="dark-content" />
)}
{state.userToken == null ? (
<NavigationContainer>
<LogonStackNavigator />
</NavigationContainer>
) : (
<NavigationContainer>
<DrawerNavigator />
</NavigationContainer>
)}
</AuthContext.Provider>
);
};
export default App;
还有我处理登录表单的SiginScreen.tsx 文件:
import React, { ReactElement } from 'react';
import { StyleSheet, KeyboardAvoidingView } from 'react-native';
import { StackNavigationProp } from '@react-navigation/stack';
import { RouteProp } from '@react-navigation/core';
import { AuthContext } from '../contexts';
import {
LogonHeader, Button, Input, Text, TextLink,
} from '../components';
import { LogonStackParamList } from '../navigation/LogonStackNavigator';
interface Props {
navigation: StackNavigationProp<LogonStackParamList, 'SignIn'>;
route: RouteProp<LogonStackParamList, 'SignIn'>;
}
const SignInScreen = ({ navigation }: Props): ReactElement => {
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const { signIn } = React.useContext(AuthContext);
return (
<KeyboardAvoidingView
style={styles.container}
behavior="padding"
>
<LogonHeader title="Se connecter" />
<Input
placeholder="E-mail"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
/>
<Input
placeholder="Mot de passe"
value={password}
onChangeText={setPassword}
secureTextEntry
/>
<Button
title="Connexion"
onPress={() => signIn({
email,
password,
})}
/>
</KeyboardAvoidingView>
);
};
export default SignInScreen;
它按预期工作,但我不知道如何处理错误情况。
目前,它只是 index.tsx 文件上的 console.log 声明。
如何正确通知SignInScreen 组件登录失败在用户端显示消息?我应该使用 redux 还是什么?
更确切地说:我想直接在SignInScreen 上放一条错误短信,以防万一失败。
【问题讨论】:
标签: reactjs typescript react-native authentication