REACT NAVIGATION August 29, 2018

【React Navigation】九、createSwitchNavigator-身份认证流程

Words count 24k Reading time 22 mins. Read count 0

大部分应用在用户访问与用户相关的数据或者其他一些私有内容时,需要先进行身份验证。通常,流程将如下所示:

  • 用户打开应用程序
  • 该应用从数据存储层加载一些身份验证的状态(例如从AsyncStorage加载)
  • 加载状态后,通过判断是否加载了有效的身份验证状态,来决定跳转到身份验证界面或者主应用界面
  • 当用户注销时,我们清除身份验证状态,并返回到身份验证界面

配置我们的导航器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import React from 'react';
import {
ActivityIndicator,
AsyncStorage,
Button,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import { createStackNavigator, createSwitchNavigator } from 'react-navigation';

class SignInScreen extends React.Component {
static navigationOptions = {
title: 'Please sign in',
};

render() {
return (
<View style={styles.container}>
<Button title="Sign in!" onPress={this._signInAsync} />
</View>
);
}

_signInAsync = async () => {
await AsyncStorage.setItem('userToken', 'abc');
this.props.navigation.navigate('App');
};
}

class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome to the app!',
};

render() {
return (
<View style={styles.container}>
<Button title="Show me more of the app" onPress={this._showMoreApp} />
<Button title="Actually, sign me out :)" onPress={this._signOutAsync} />
</View>
);
}

_showMoreApp = () => {
this.props.navigation.navigate('Other');
};

_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
}

class OtherScreen extends React.Component {
static navigationOptions = {
title: 'Lots of features here',
};

render() {
return (
<View style={styles.container}>
<Button title="I'm done, sign me out" onPress={this._signOutAsync} />
<StatusBar barStyle="default" />
</View>
);
}

_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
}

class AuthLoadingScreen extends React.Component {
constructor() {
super();
this._bootstrapAsync();
}

// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
const userToken = await AsyncStorage.getItem('userToken');

// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(userToken ? 'App' : 'Auth');
};

// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});

const AppStack = createStackNavigator({ Home: HomeScreen, Other: OtherScreen });
const AuthStack = createStackNavigator({ SignIn: SignInScreen });

export default createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
);

你可能还不熟悉SwitchNavigator。SwitchNavigator是一个一次只显示一个页面的导航器。在默认情况下,它不处理后退操作,并在您切换时将路由重置为其默认状态。这正是我们在身份验证流程中想要的行为:当用户登录后,我们想要丢弃整个验证流程,卸载所有相关的页面,当我们按下返回键时,我们希望不再返回到身份验证流程。 我们使用navigate在SwitchNavigator中切换路由。我们将initialRouteName设置为’AuthLoading’,因为我们将从该屏幕组件内的持久存储中获取我们的身份验证状态。

增加其他的一些组件

我们的App和Auth路线都是堆栈导航器,但你可以在这里做任何你喜欢的事情。 如上所述,您可能希望您的身份验证路由成为密码重置,注册等的堆栈。同样,对于您的应用,您可能有多个屏幕。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import React from 'react';
import {
ActivityIndicator,
AsyncStorage,
Button,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import { createStackNavigator, createSwitchNavigator } from 'react-navigation';

class SignInScreen extends React.Component {
static navigationOptions = {
title: 'Please sign in',
};

render() {
return (
<View style={styles.container}>
<Button title="Sign in!" onPress={this._signInAsync} />
</View>
);
}

_signInAsync = async () => {
this.props.navigation.navigate('SignSecond');
};
}

class SignInSecondScreen extends React.Component {
static navigationOptions = {
title: 'sign in second',
};

render() {
return (
<View style={styles.container}>
<Button title="Sign in!" onPress={this._signInAsync} />
</View>
);
}

_signInAsync = async () => {
await AsyncStorage.setItem('userToken', 'abc');
this.props.navigation.navigate('App');
};
}

class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome to the app!',
};

render() {
return (
<View style={styles.container}>
<Button title="Show me more of the app" onPress={this._showMoreApp} />
<Button title="Actually, sign me out :)" onPress={this._signOutAsync} />
</View>
);
}

_showMoreApp = () => {
this.props.navigation.navigate('Other');
};

_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
}

class OtherScreen extends React.Component {
static navigationOptions = {
title: 'Lots of features here',
};

render() {
return (
<View style={styles.container}>
<Button title="I'm done, sign me out" onPress={this._signOutAsync} />
<StatusBar barStyle="default" />
</View>
);
}

_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
}

class AuthLoadingScreen extends React.Component {
constructor() {
super();
this._bootstrapAsync();
}

// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
const userToken = await AsyncStorage.getItem('userToken');

// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(userToken ? 'App' : 'Auth');
};

// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});

const AppStack = createStackNavigator({ Home: HomeScreen, Other: OtherScreen });
const AuthStack = createStackNavigator({ SignIn: SignInScreen, SignSecond: SignInSecondScreen });

export default createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
);
0%