首页 > 解决方案 > 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 可用于文件之间的其他组件?

标签: react-nativereact-native-navigationreact-context

解决方案


您可以将上下文创建放在单独的文件中

//AuthContext.js
const AuthContext = createContext();
export default AuthContext;

在 app.js 中,您可以简单地导入它并使用它

import AuthContext from './AuthContext.js';

您也可以对 login.js 执行相同的操作然后它将按预期工作。


推荐阅读