KIRA WRITES

How to Integrate Firebase with Expo React Native

react logo, expo logo, firebase logo

I worked on an app dev project recently that demanded fast turn around and cross-platform compatibility, so using React Native with the Expo managed workflow was the most efficient choice. However, as soon as I needed to integrate Firebase with Expo React Native, a problem came up. The most popular library, React Native Firebase, is not compatible with the Expo managed workflow. What to do?

Fortunately, the react-firebase-hooks library comes to rescue. If you are already using hooks in your React development, the benefits are clear:

  • you can access and manage states in a function, which means you no longer need to write classes for your components;
  • you can control when the side effect functions are called with useEffect;
  • you can write custom hooks that are reusable in different functional components. react-firebase-hooks provide hooks that act as wrappers and listeners for Firebase methods. This tutorial will walk you through how to manage Firebase Auth's auth state using react-firebase-hooks.

Create a Firebase Project

Add a project, choose your settings, register your app, and what we need here is the firebaseConfig information. We are going to copy and paste this information into our project.

const firebaseConfig = {
  apiKey: "[APIKEY]",
  authDomain: "[AUTHDOMAIN]",
  databaseURL: "[DATABASEURL]",
  projectId: "[PROJECTID]",
  storageBucket: "[STORAGEBUCKET]",
  messagingSenderId: "[MESSAGINGSENDERID]",
  appId: "[APPID]",
  measurementId: "[MEASUREMENTID]",
};

Add Firebase Configuration to Your Project Install the Firebase SDK. I am using npm:

$ npm install --save firebase

Create a config folder at the root of your Expo React native project. Inside the config folder, create a file firebase.tsx (or firebase.js if you are not using Typescript). You will store your Firebase configuration information here.

import * as firebase from "firebase";

// Config info unique to your project
const firebaseConfig = {
  apiKey: "[APIKEY]",
  authDomain: "[AUTHDOMAIN]",
  databaseURL: "[DATABASEURL]",
  projectId: "[PROJECTID]",
  storageBucket: "[STORAGEBUCKET]",
  messagingSenderId: "[MESSAGINGSENDERID]",
  appId: "[APPID]",
  measurementId: "[MEASUREMENTID]",
};

// Initialize Firebase
const Firebase = firebase.initializeApp(firebaseConfig);

// Export the Firebase App so the rest of the app can have access to it
export default Firebase;

Using the Auth Hook

Install the react-firebase-hooks library to your project:

$ npm install --save react-firebase-hooks

In your App.tsx (or App.js), import the useAuthState hook and the already initialized Firebase project from the config folder:

import { useAuthState } from "react-firebase-hooks/auth";
import Firebase from "./config/firebase";
import React from "react";

export default function App() {
  // useAuthState hook takes a Firebase auth instance to monitor
  const [user, loading, error] = useAuthState(Firebase.auth());
  return (
    <SafeAreaProvider>
      <Navigation />
      <StatusBar />
    </SafeAreaProvider>
  );
}

Now you can access the current user object in user! If the user is logged in, user returns firebase.User, or undefined if not.

Note: Refer to the react-firebase-hooks auth documentation for specific usage and examples.

Making the User Object Globally Available Using React Context

In the step above, the reason we initialized the useAuthState hook in App.tsx is that it is the top-level component. The next step is to pass the user object down to the child screens. We will use React Context, designed to "share data that can be considered 'global' for a tree of React components." First, we create a User Context. Create a folder context in the root directory of our react native project. Then, create the file UserContext.tsx in the context folder.

import React from "react";
import * as firebase from "firebase";

export default (React.createContext < undefined) | (firebase.User > undefined);

Our App.tsx will be the UserContext Provider, and the value we want to pass into the provider is the user object initialized by Firebase. In our App.tsx, we will wrap the return view in a UserContext.Provider component, and pass user as the value to the provider:

import { useAuthState } from "react-firebase-hooks/auth";
import Firebase from "./config/firebase";
import React from "react";

export default function App() {
  // useAuthState hook takes a Firebase auth instance to monitor
  const [user, loading, error] = useAuthState(Firebase.auth());
  return (
    <UserContext.Provider value={user}>
    <SafeAreaProvider>
      <Navigation />
      <StatusBar />
    </SafeAreaProvider>
    <UserContext.Provider>
  );
}

The child components (AKA the screens) are consumers of the UserContext. To access user information in a child component, import the UserContext hook, and then call useContext(UserContext);. The code below is a bare bone log in screen:

import { useContext } from "react";
import UserContext from "../context/UserContext";
import React from "react";

export default function LogInScreen() {
  // Now you have access to the user object!
  const user = useContext(UserContext);

  // Hooks for tracking email and password changes
  const [email, onChangeEmail] = React.useState("");
  const [password, onChangePassword] = React.useState("");

  function handleSignIn(
    email: string,
    password: string,
    user: undefined | firebase.User
  ) {
    Firebase.auth()
      .signInWithEmailAndPassword(email, password)
      .then(() => {
        alert("logged in!");
      })
      .catch((error) => alert(error));
  }
  return (
    <SafeAreaView>
      <TextInput value={email} onChangeText={(email) => onChangeEmail(email)}></TextInput>
      <TextInput value={password} onChangeText={(password) => onChangePassword(password)}></TextInput>
      <TouchableHighlight onPress={() => handleSignIn(email, password, user)}><TouchableHighlight>
    </SafeAreaView>
  );
}

You can now log in a user.

Conclusion

Congrats for finishing the tutorial!

  • We learned about using React Hooks and why they are superior;
  • We used React Context to manage global information;
  • Now we can incorporate Firebase into our Expo React Native project!