react-native - React Native Context,如何在多个嵌套文件和组件之间共享上下文
问题描述
我对本机反应很陌生,并且我坚持在不同文件中的组件之间传递上下文,基本上我在反应导航 auth-flow https://reactnavigation.org/docs/auth-flow/之后构建登录流 我的场景看起来像跟随:
在 App.js 中,带有 Login/Register/Home 的堆栈屏幕,根据登录状态显示 Login/Register 或 Home 主屏幕由一个抽屉组件组成,该组件是一个抽屉,使用自定义抽屉和两个组件(Home 和 About)
//VARIOUS IMPORT
const Drawer = createDrawerNavigator();
const HeaderOption = () => ({
headerShown: false,
// animationTypeForReplace: state.isSignout ? 'pop' : 'push',
});
const AppStack = createStackNavigator();
const AuthContext = createContext();
//THE DRAWER FOR HOME
function DrawerNavigator(props) {
return (
<Drawer.Navigator
initialRouteName="Home"
drawerContent={(props) => MyDrawer(props)}
>
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="About" component={About} />
</Drawer.Navigator>
);
}
//MAIN APP
export default function App({ navigation }) {
const [state, dispatch] = useReducer(
(prevState, action) => {
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,
};
}
},
{
isLoading: true,
isSignout: false,
userToken: null,
}
);
useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
const bootstrapAsync = async () => {
let userToken;
try {
userToken = await AsyncStorage.getItem('userToken');
} catch (e) {
}
dispatch({ type: 'RESTORE_TOKEN', token: userToken });
};
bootstrapAsync();
}, []);
const authContext = useMemo(
() => ({
signIn: async (data) => {
// LOGIN PROCEDURE
dispatch({ type: 'SIGN_IN', token: 'dummy-auth-token' });
},
signOut: () => dispatch({ type: 'SIGN_OUT' }),
signUp: async (data) => {
// SUBSCRIBE PROCEDURE
dispatch({ type: 'SIGN_IN', token: 'dummy-auth-token' });
},
}),
[]
);
if (state.isLoading) {
// We haven't finished checking for the token yet
return (
<View>
<Text>Loading</Text>
</View>
);
}
return (
<AuthContext.Provider value={authContext}>
<NavigationContainer>
<AppStack.Navigator initialRouteName="Login">
{state.userToken == null ? (
<>
<AppStack.Screen
name="Login"
component={LoginScreen}
options={HeaderOption}
/>
<AppStack.Screen
name="Register"
component={RegisterScreen}
options={HeaderOption}
/>
</>
) : (
<AppStack.Screen
name="HomeApp"
component={DrawerNavigator}
options={HeaderOption}
/>
)}
</AppStack.Navigator>
</NavigationContainer>
</AuthContext.Provider>
);
}
在 LoginScreen.js 中有效的登录屏幕(如果未登录,则会在应用启动时显示)
//import
export default function LoginScreen(props) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { signIn } = useContext(AuthContext);
return (
<View
style={{
flex: 1,
backgroundColor: Constants.MAIN_GREEN,
}}
>
<View style={{ ...styles.container }}>
<StatusBar hidden={true} />
<View style={{ ...styles.logoContainer }}>
<Image
style={styles.logoIcon}
source={require('../assets/logo_popeating_amp.png')}
/>
</View>
<View style={{ ...styles.inputContainer }}>
<Image
style={styles.inputIcon}
source={require('../assets/mail.png')}
/>
<TextInput
autoFocus={true}
placeholder="Email address"
onChangeText={(email) => setEmail(email)}
value={email}
label="Email"
style={styles.inputs}
keyboardType={'email-address'}
/>
</View>
<View style={{ ...styles.inputContainer }}>
<Image
style={styles.inputIcon}
source={require('../assets/password.png')}
/>
<TextInput
placeholder="Password"
onChangeText={(password) => setPassword(password)}
value={password}
secureTextEntry={true}
label="Password"
style={styles.inputs}
/>
</View>
<TouchableHighlight
style={[styles.buttonContainer, styles.loginButton]}
onPress={() => signIn({ email, password })}
underlayColor={Constants.HI_COLOR}
>
<Text style={styles.loginText}>LOGIN</Text>
</TouchableHighlight>
<TouchableHighlight
style={styles.buttonContainer}
onPress={() => props.navigation.navigate('HomeApp')}
underlayColor={Constants.HI_COLOR}
>
<Text>Forgot your password?</Text>
</TouchableHighlight>
<TouchableHighlight
style={styles.buttonContainer}
onPress={() => props.navigation.navigate('Register')}
underlayColor={Constants.HI_COLOR}
>
<Text>Register</Text>
</TouchableHighlight>
</View>
</View>
);
}
const styles = StyleSheet.create({
//styles
});
在 DrawerContent.js 中,主页的抽屉包含指向主页的链接、指向 About 的链接、指向 Logout 的链接
在 Home.js 中,主页面是 Drawer 的初始路由
每次我尝试启动应用程序时,错误都是 未处理的承诺拒绝:ReferenceError:找不到变量:AuthContext
似乎 LoginScreen 无法访问 AuthContext,我怎样才能让 AuthContext 可用于文件之间的其他组件?
解决方案
您可以将上下文创建放在单独的文件中
//AuthContext.js
const AuthContext = createContext();
export default AuthContext;
在 app.js 中,您可以简单地导入它并使用它
import AuthContext from './AuthContext.js';
您也可以对 login.js 执行相同的操作然后它将按预期工作。
推荐阅读
- mysql - 如何在不停机的情况下更改 AWS RDS 上的主密码?
- reactjs - 反应JS
组件未定义? - vb.net - 根据列表框访问数据库 vb.net 中的选择显示组框
- ruby-on-rails - 根据用户日期输入安排 Rails 电子邮件/剩余邮件
- python - 在 dockerized python 环境中使用 LocalStack 进行测试
- angular - 如何使用 @azure/msal-angular 获取用户的 AAD 成员资格
- python - 当我的程序没有告诉我任何错误时,我该如何修复它
- python - cv2 : cv2Color()
- loops - 用于跳转时,汇编比较相等总是不相等
- php - 将临时 AWS 凭证输出到