当登录页面放置在 UserProvider Fallback Prop 上时,尝试从登录页面导航到注册页面时,导航对象未初始化错误

问题描述 投票:0回答:1

我已经实现了领域设备同步,并且我正在使用电子邮件/密码身份验证方法来登录。我按照模板中提供的步骤进行操作,并将导航容器放置在 Realm 的 AppProvider 和 User Provider 组件的顶层。当用户未登录时,我将显示登录页面。但是,我无法移动到从登录页面导航的注册页面。

App.tsx 代码

import "react-native-gesture-handler";
import { NavigationContainer } from "@react-navigation/native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import NativeStack from "./src/routes/NativeStack";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { PaperProvider } from "react-native-paper";
import { AppProvider, UserProvider } from "@realm/react";
import { appId, baseUrl } from "./atlasConfig.json";
import Login from "./src/screens/authScreen/Login";
import realmContext from "./src/data/dbContext";
import Loading from "./src/screens/loadingScreen/Loading";

export default function App() {
  // Getting Realm Provider
  const { RealmProvider } = realmContext;

  return (
    <PaperProvider>
      <SafeAreaProvider>
        <GestureHandlerRootView style={{ flex: 1 }}>
          <NavigationContainer>
            <AppProvider id={appId} baseUrl={baseUrl}>
              <UserProvider fallback={Login}>
                <RealmProvider
                  sync={{
                    flexible: true,
                    onError: (_, error) => {
                      console.log(error);
                    },
                    initialSubscriptions: {
                      update(subs, realm) {
                        subs.add(realm.objects("Company")),
                          subs.add(realm.objects("Purchase")),
                          subs.add(realm.objects("Payment"));
                      },
                    },
                  }}
                  fallback={Loading}
                >
                  <NativeStack />
                </RealmProvider>
              </UserProvider>
            </AppProvider>
          </NavigationContainer>
        </GestureHandlerRootView>
      </SafeAreaProvider>
    </PaperProvider>
  );
}

Login.tsx 代码

import Realm from "realm";
import {
  Keyboard,
  NativeSyntheticEvent,
  StyleSheet,
  TextInputChangeEventData,
  TouchableWithoutFeedback,
  View,
} from "react-native";
import React, { useCallback, useState } from "react";
import { StackActions, useNavigation } from "@react-navigation/native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Button, Text, TextInput } from "react-native-paper";
import { useApp } from "@realm/react";

const Login = () => {
  // Realm App Context
  const app = useApp();

  // Navigation
  const nav = useNavigation();

  // Form input variables
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  // Toggle Password Visibility
  const [passwordVisibility, setPasswordVisibility] = useState(true);

  // Action Handlers
  const formClear = () => {
    setEmail("");
    setPassword("");
    setPasswordVisibility(true);
  };
  const registerHandler = () => {
    nav.dispatch(StackActions.replace("Register"));
    formClear();
  };
  const loginHandler = useCallback(async () => {
    const creds = Realm.Credentials.emailPassword({ email, password });
    await app.logIn(creds);
    formClear();
  }, [app, email, password]);

  return (
    <TouchableWithoutFeedback
      onPress={Keyboard.dismiss}
      style={styles.containerWrapper}
    >
      <SafeAreaView style={styles.containerWrapper}>
        <View style={styles.container}>
          <View style={styles.headerContainer}>
            <Text variant="titleLarge" style={styles.headerLabel}>
              Register
            </Text>
          </View>
          <View>
            <TextInput
              label="Email"
              placeholder="Email"
              value={email}
              autoCapitalize="none"
              onChange={(e: NativeSyntheticEvent<TextInputChangeEventData>) => {
                setEmail(e.nativeEvent.text);
              }}
            />
            <TextInput
              label="Password"
              placeholder="Password"
              value={password}
              autoCapitalize="none"
              secureTextEntry={passwordVisibility}
              onChange={(e: NativeSyntheticEvent<TextInputChangeEventData>) => {
                setPassword(e.nativeEvent.text);
              }}
              right={
                <TextInput.Icon
                  icon="eye"
                  onPress={() => {
                    setPasswordVisibility((previousState) => !previousState);
                  }}
                />
              }
            />
          </View>
          <View style={styles.buttonContainer}>
            <Button mode="contained" onPress={loginHandler}>
              Login
            </Button>
            <Button mode="outlined" onPress={registerHandler}>
              Don't have an Account? Register
            </Button>
          </View>
        </View>
      </SafeAreaView>
    </TouchableWithoutFeedback>
  );
};

export default Login;

const styles = StyleSheet.create({
  containerWrapper: {
    flex: 1,
  },
  container: {
    flex: 1,
  },
  headerContainer: {},
  headerLabel: {},
  inputContainer: {
    gap: 20,
  },
  buttonContainer: {},
  button: {},
});

Signup.tsx 代码

import Realm from "realm";
import {
  Alert,
  Keyboard,
  NativeSyntheticEvent,
  StyleSheet,
  TextInputChangeEventData,
  TouchableWithoutFeedback,
  View,
} from "react-native";
import React, { useCallback, useState } from "react";
import { SafeAreaView } from "react-native-safe-area-context";
import { Button, Text, TextInput } from "react-native-paper";
import { StackActions, useNavigation } from "@react-navigation/native";
import { useApp } from "@realm/react";

const Register = () => {
  // App Context for Realm
  const app = useApp();

  // Navigation
  const nav = useNavigation();

  // Form input variables
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");

  // Toggle Password Visibility
  const [passwordVisibility, setPasswordVisibility] = useState(true);
  const [confirmPasswordVisibility, setConfirmPasswordVisibility] =
    useState(true);

  // Action Handlers
  const formClear = () => {
    setEmail("");
    setPassword("");
    setConfirmPassword("");
    setPasswordVisibility(true);
    setConfirmPasswordVisibility(true);
  };

  const signIn = useCallback(async () => {
    const creds = Realm.Credentials.emailPassword({ email, password });
    await app.logIn(creds);
  }, [app, email, password]);

  const registerHandler = useCallback(async () => {
    try {
      await app.emailPasswordAuth.registerUser({ email, password });
      await signIn();
      formClear();
    } catch (error: any) {
      Alert.alert(`Failed to Register: ${error?.message}`);
    }
  }, [signIn, app, email, password]);
  const loginHandler = () => {
    nav.dispatch(StackActions.replace("Login"));
    formClear();
  };

  return (
    <TouchableWithoutFeedback
      onPress={Keyboard.dismiss}
      style={styles.containerWrapper}
    >
      <SafeAreaView style={styles.containerWrapper}>
        <View style={styles.container}>
          <View style={styles.headerContainer}>
            <Text variant="displayLarge" style={styles.headerLabel}>
              Register
            </Text>
          </View>
          <View style={styles.formContainer}>
            <TextInput
              label="Email"
              placeholder="Email"
              value={email}
              autoCapitalize="none"
              onChange={(e: NativeSyntheticEvent<TextInputChangeEventData>) => {
                setEmail(e.nativeEvent.text);
              }}
            />
            <TextInput
              label="Password"
              placeholder="Password"
              value={password}
              autoCapitalize="none"
              secureTextEntry={passwordVisibility}
              onChange={(e: NativeSyntheticEvent<TextInputChangeEventData>) => {
                setPassword(e.nativeEvent.text);
              }}
              right={
                <TextInput.Icon
                  icon="eye"
                  onPress={() => {
                    setPasswordVisibility((previousState) => !previousState);
                  }}
                />
              }
            />
            <TextInput
              label="Confirm Password"
              placeholder="Re-Enter Password"
              value={confirmPassword}
              autoCapitalize="none"
              secureTextEntry={confirmPasswordVisibility}
              onChange={(e: NativeSyntheticEvent<TextInputChangeEventData>) => {
                setConfirmPassword(e.nativeEvent.text);
              }}
              right={
                <TextInput.Icon
                  icon="eye"
                  onPress={() => {
                    setConfirmPasswordVisibility(
                      (previousState) => !previousState
                    );
                  }}
                />
              }
            />
          </View>
          <View style={styles.buttonContainer}>
            <Button mode="contained" onPress={registerHandler}>
              Register
            </Button>
            <Button mode="outlined" onPress={loginHandler}>
              Already have an Account? Login
            </Button>
          </View>
        </View>
      </SafeAreaView>
    </TouchableWithoutFeedback>
  );
};

export default Register;

const styles = StyleSheet.create({
  containerWrapper: {
    flex: 1,
  },
  container: {
    flex: 1,
  },
  headerContainer: {
    height: 80,
  },
  headerLabel: {},
  inputContainer: {
    gap: 20,
  },
  buttonContainer: {},
  button: {},
  formContainer: {
    flex: 1,
    gap: 20,
  },
});

我尝试将导航容器移至领域提供程序和应用程序提供程序上方,以查看是否在之后提供了导航对象。目前还没有解决方案。

react-native realm react-native-navigation mongodb-atlas realm-mobile-platform
1个回答
0
投票

我稍后会发布这个答案。回退下 Realm 的 UserProvider 需要单独的导航堆栈设置,因此我遇到了未初始化导航对象错误的问题。

我只需将另一个带有单独导航容器的单独导航堆栈添加到后备选项即可解决此问题。

© www.soinside.com 2019 - 2024. All rights reserved.