skip to Main Content

I have implemented realm device sync and I am using email/password authentication method to login. I am following the steps provided in the template and I have placed the Navigation Container at Top level that Realm’s AppProvider and User Provider Component. When the user is not logged in I am being show the Login page. However I am unable to move to Signup Page that is being navigated from Login Page.

Code for 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>
  );
}

code for 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: {},
});

code for 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,
  },
});

I tried moving the navigation container above the Realm Provider and App Provider to see if the navigation object is provided post that. No resolution as of now yet.

2

Answers


  1. Chosen as BEST ANSWER

    I am posting this answer at a later point of time. The UserProvider of Realm under fallback requires a separate navigation stack setup and it was because of this I had the issue of uninitialised navigation object error.

    I just had to add another separate navigation stack with a separate navigation container to the fallback option to resolve this issue.


  2. Can you provide the code demonstrating exactly how you did this?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search