useContext的上下文未传递给Provider中的子级

时间:2020-10-12 15:48:49

标签: react-native react-hooks react-navigation

我正在尝试将上下文传递给内的子级,但是在调用useContext(AuthContext)时会被告知未找到变量AuthContext。

App.js

在此文件中,我将调用AppNavigator,其中包含了我所有的导航内容

export default function App() {
  return (
    <>
      <IconRegistry icons={EvaIconsPack} />
      <ApplicationProvider {...eva} theme={{ ...eva.dark, ...theme }}>
        <AppNavigator />
      </ApplicationProvider>
    </>
  );
}

AppNavigator.js

此文件中包含我的导航器,该导航器根据用户是否登录来呈现正确的屏幕。现在,我仅在使用登录功能。

export default function AppNavigator({ navigation, route }) {
  const [loading, setLoading] = useState(true);
  const [user, setUser] = useState(false);
  const AuthContext = createContext();

  const [state, dispatch] = useReducer(
    (prevState, action) => {
      switch (action.type) {
        case "RESTORE_TOKEN":
          return {
            ...prevState,
            userToken: action.token,
            isLoading: false,
          };
        case "LOG_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) {
        // Restoring token failed
      }

      // After restoring token, we may need to validate it in production apps

      // This will switch to the App screen or Auth screen and this loading
      // screen will be unmounted and thrown away.
      dispatch({ type: "RESTORE_TOKEN", token: userToken });
    };

    bootstrapAsync();
  }, []);

  const authContext = useMemo(
    () => ({
      login: async (email, password) => {
        // 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

        firebase
          .auth()
          .signInWithEmailAndPassword(email, password)
          .then((response) => {
            const uid = response.user.uid;
            const userToken = response.user;
            const usersRef = firebase.firestore().collection("users");
            usersRef
              .doc(uid)
              .get()
              .then((firestoreDocument) => {
                if (!firestoreDocument.exists) {
                  alert("User does not exist anymore.");
                  return;
                }
                const user = firestoreDocument.data();

                //navigation.navigate("Home", { user: user });

                //console.log(response);
              })
              .catch((error) => {
                alert(error);
              });
          })
          .catch((error) => {
            alert(error);
          });
        const userData = { email, password };
        console.log("This is before the store");
        console.log(userData);
        await AsyncStorage.setItem("userData", JSON.stringify(userData));
        dispatch({ type: "LOG_IN", token: JSON.stringify(userToken) });
      },
      signOut: () => dispatch({ type: "SIGN_OUT" }),
      join: 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

        dispatch({ type: "LOG_IN", token: "dummy-auth-token" });
      },
    }),
    []
  );

这是我设置导航器的地方,我试图在登录屏幕中调用useContext。

  return (
    <NavigationContainer>
      <AuthContext.Provider value={authContext}>
        <Stack.Navigator headerMode={false}>
          {state.userToken == null ? (
            <>
              <Stack.Screen name="Welcome" component={WelcomeScreen} />
              <Stack.Screen name="Login" component={Login} />
              <Stack.Screen name="Join" component={Join} />
            </>
          ) : (
            <Stack.Screen name="Home" component={Home} />
          )}
        </Stack.Navigator>
      </AuthContext.Provider>
    </NavigationContainer>
  );
}

Login.js

我尝试调用AuthContext中定义的登录函数,但是收到错误ReferenceError: Can't find variable: AuthContext,我相信这意味着它没有从父级获取上下文。

export default function Login({ navigation }) {
  console.log("got this far?");

  const { login } = useContext(AuthContext);

  
  const [secureTextEntry, setSecureTextEntry] = React.useState(true);

  const renderEyeIcon = (props) => (
    <TouchableWithoutFeedback onPress={toggleSecureEntry}>
      <Icon {...props} name={secureTextEntry ? "eye-off" : "eye"} />
    </TouchableWithoutFeedback>
  );

  const toggleSecureEntry = () => {
    setSecureTextEntry(!secureTextEntry);
  };

  return (
    <Layout style={styles.container}>
      <Image
        source={require("../../assets/FullLogo.png")}
        style={styles.image}
      ></Image>

      {/* <Layout > */}
      {/* <KeyboardAvoidingView behavior="height" style={styles.form}> */}
      <AppForm
        initialValues={{
          email: "",
          password: "",
        }}
        //onSubmit={(values) => handleLogin(values)}
        onSubmit={(values) => {
          login(values.email, values.password);
        }}
        validationSchema={validationSchema}
      >
        <FormField
          name="email"
          placeholder="Email"
          textContentType="emailAddress"
        />
        <FormField
          name="password"
          placeholder="Password"
          accessoryRight={renderEyeIcon}
          secureTextEntry={secureTextEntry}
        />
        <SubmitButton title="Login" />
      </AppForm>
      {/* </KeyboardAvoidingView> */}
      {/* </Layout> */}
    </Layout>
  );
}

感谢您的帮助!

0 个答案:

没有答案