使用 Context Provider 包装 React Native 应用程序
Wrapping React Native app with Context Provider
我一直在关注一些 simple tutorial (full working source code) 以了解如何在我的 React Native 应用程序中使用 React 的上下文以及处理身份验证。
此示例将有状态组件用于视图并处理组件本身内的应用程序路由,例如 SignInScreen.js
:
/* SignInScreen.js */
export default class SignInScreen extends React.Component {
static navigationOptions = {
title: 'Please sign in',
};
_signInAsync = async (saveToken) => {
saveToken()
.then((data) => {
// ROUTE USER TO "PROTECTED" PART OF THE APP
this.props.navigation.navigate('App');
})
.catch((error) => {
this.setState({ error })
})
};
render() {
return (
<View style={styles.container}>
<MyContext.Consumer>
{context => ((
<Button title="Sign in!" onPress={() => this._signInAsync(context.saveToken)} />
))}
</MyContext.Consumer>
</View>
);
}
};
我尝试将此组件转换为功能组件,并将登录逻辑移动到我的上下文提供程序中,如下所示:
/* SignInScreen.js - MODIFIED */
import React from 'react';
import { Button, View } from 'react-native';
import { MyContext } from '../Provider';
export default const LoginScreen = () => {
return (
<View>
<MyContext.Consumer>
{context => {
return (
<Button
onPress={() => context.signIn()}
title="Sign In"
/>
)
}
}
</MyContext.Consumer>
</View>
)
};
/* Provider.js */
import React from 'react';
import { AsyncStorage } from 'react-native';
export const MyContext = React.createContext();
export default class MyProvider extends React.Component {
constructor(props) {
super(props);
this.getToken = () => AsyncStorage.getItem('userToken');
this.saveToken = () => AsyncStorage.setItem('userToken', 'abc');
this.removeToken = () => AsyncStorage.removeItem('userToken');
this.signIn = () => {
this.saveToken()
.then((data) => {
// this.props.navigation DOES NOT EXIST!!! :(
this.props.navigation.navigate('App');
})
.catch((error) => this.setState({ error }));
};
this.state = {
token: '',
signIn: this.signIn,
};
}
componentWillMount() {
AsyncStorage.getItem('userToken')
.then((token) => {
this.setState({ token })
})
.catch(error => {
this.setState({ error })
})
}
render() {
return (
<MyContext.Provider value={this.state}>
{this.props.children}
</MyContext.Provider>
);
}
}
当我按下 "Sign In" 按钮时,我的提供商在我尝试重定向用户 (this.props.navigation.navigate('App');
) 时出错,因为 this.props.navigation
不存在。
据我所知,发生这种情况是因为我没有用上下文正确包装我的应用程序。
这是我的主要 App.js
文件:
/* App.js */
import React from 'react';
import { View } from 'react-native';
import MyContext from './Provider';
import AppNavigator from './navigation/AppNavigator';
export default class App extends React.Component {
render() {
return (
<MyContext>
<View>
<AppNavigator />
</View>
</MyContext>
);
}
}
和我的 AppNavigator.js
:
/* AppNavigator.js */
import React from 'react';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import AuthLoadingScreen from '../screens/AuthLoadingScreen';
import Auth from './AuthNavigator';
import App from './AppTabNavigator';
export default createAppContainer(createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
Auth,
App,
},
{
initialRouteName: 'AuthLoading',
}
));
(AuthNavigator
和 AppTabNavigator
仅包含 createStackNavigator()
,其中定义了我的屏幕。)
我的问题是:如何用我的 Context 包装这个应用程序,以便 Context Provider 始终知道 navigation
prop,这样我就可以从 Context Provider 本身处理登录和注销以及路由用户?
我使用 NavigationActions
解决了这个问题,非常有用的内置模块专为此目的而设计。
我一直在关注一些 simple tutorial (full working source code) 以了解如何在我的 React Native 应用程序中使用 React 的上下文以及处理身份验证。
此示例将有状态组件用于视图并处理组件本身内的应用程序路由,例如 SignInScreen.js
:
/* SignInScreen.js */
export default class SignInScreen extends React.Component {
static navigationOptions = {
title: 'Please sign in',
};
_signInAsync = async (saveToken) => {
saveToken()
.then((data) => {
// ROUTE USER TO "PROTECTED" PART OF THE APP
this.props.navigation.navigate('App');
})
.catch((error) => {
this.setState({ error })
})
};
render() {
return (
<View style={styles.container}>
<MyContext.Consumer>
{context => ((
<Button title="Sign in!" onPress={() => this._signInAsync(context.saveToken)} />
))}
</MyContext.Consumer>
</View>
);
}
};
我尝试将此组件转换为功能组件,并将登录逻辑移动到我的上下文提供程序中,如下所示:
/* SignInScreen.js - MODIFIED */
import React from 'react';
import { Button, View } from 'react-native';
import { MyContext } from '../Provider';
export default const LoginScreen = () => {
return (
<View>
<MyContext.Consumer>
{context => {
return (
<Button
onPress={() => context.signIn()}
title="Sign In"
/>
)
}
}
</MyContext.Consumer>
</View>
)
};
/* Provider.js */
import React from 'react';
import { AsyncStorage } from 'react-native';
export const MyContext = React.createContext();
export default class MyProvider extends React.Component {
constructor(props) {
super(props);
this.getToken = () => AsyncStorage.getItem('userToken');
this.saveToken = () => AsyncStorage.setItem('userToken', 'abc');
this.removeToken = () => AsyncStorage.removeItem('userToken');
this.signIn = () => {
this.saveToken()
.then((data) => {
// this.props.navigation DOES NOT EXIST!!! :(
this.props.navigation.navigate('App');
})
.catch((error) => this.setState({ error }));
};
this.state = {
token: '',
signIn: this.signIn,
};
}
componentWillMount() {
AsyncStorage.getItem('userToken')
.then((token) => {
this.setState({ token })
})
.catch(error => {
this.setState({ error })
})
}
render() {
return (
<MyContext.Provider value={this.state}>
{this.props.children}
</MyContext.Provider>
);
}
}
当我按下 "Sign In" 按钮时,我的提供商在我尝试重定向用户 (this.props.navigation.navigate('App');
) 时出错,因为 this.props.navigation
不存在。
据我所知,发生这种情况是因为我没有用上下文正确包装我的应用程序。
这是我的主要 App.js
文件:
/* App.js */
import React from 'react';
import { View } from 'react-native';
import MyContext from './Provider';
import AppNavigator from './navigation/AppNavigator';
export default class App extends React.Component {
render() {
return (
<MyContext>
<View>
<AppNavigator />
</View>
</MyContext>
);
}
}
和我的 AppNavigator.js
:
/* AppNavigator.js */
import React from 'react';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import AuthLoadingScreen from '../screens/AuthLoadingScreen';
import Auth from './AuthNavigator';
import App from './AppTabNavigator';
export default createAppContainer(createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
Auth,
App,
},
{
initialRouteName: 'AuthLoading',
}
));
(AuthNavigator
和 AppTabNavigator
仅包含 createStackNavigator()
,其中定义了我的屏幕。)
我的问题是:如何用我的 Context 包装这个应用程序,以便 Context Provider 始终知道 navigation
prop,这样我就可以从 Context Provider 本身处理登录和注销以及路由用户?
我使用 NavigationActions
解决了这个问题,非常有用的内置模块专为此目的而设计。