Declaratively Render Your Firebase Auth, Database & Firestore Data with @react-firebase.
Tags: react, javascript, firebase, webdev
Published: 2018-10-13 12:48:59

---
title: Declaratively Render Your Firebase Auth, Database & Firestore Data with @react-firebase.
published: true
description: A composable, component based React API over Firebase Auth, Realtime Database and Firestore.
tags: react,javascript,firebase,webdev
---


## TLDR;

[@react-firebase](https://react-firebase-js.com) was released to make integrating Firebase in your React App fast & easy 🎉.

If you use React & Firebase, go [check it out](https://react-firebase-js.com) !

## The longer version

I ❤️ Firebase & React but getting them to work together on relatively large codebases with other contributors tends to lead to :

1. 🍝 Un-necessary complexity in your codebase 
2. 🐛 Subtle bugs with subscription management and inter-resource dependencies.
3. 🎃 Zombie listeners sticking around when your UI doesn't need them.


[`@react-firebase`](https://react-firebase-js.com) offers small, typed, well-tested composable components that allow easy integration of Firebase Auth, Realtime Database and/or Firestore in your React or React Native app.

## Overview

`@react-firebase/auth`, `@react-firebase/database`, `@react-firebase/firestore` export `Provider` and `Consumer` Components.

### Providers

The `Provider` components take in `firebase` and firebase config options props and should be rendered once in your app as an ancestor to your `Consumer` components.

#### How do I get my Firebase config ?

##### Web or React Native with Expo

If you're using [firebase](https://www.npmjs.com/package/firebase)

Change `PROJECT_NAME` to your project name and grab your firebase config here :

`https://console.firebase.google.com/project/PROJECT_NAME/settings/general/`

It should look something like this :

```javascript
// Firebase Config
const config = {
  apiKey: "API_KEY",
  projectId: "PROJECT_ID",
  databaseURL: "DATABASE_URL",
  authDomain: "AUTH_DOMAIN",
  // OPTIONAL
  storageBucket: "STORAGE_BUCKET",
  messagingSenderId: "MESSAGING_SENDER_ID"
};
```


##### React Native Firebase

If you're using [react-native-firebase](https://rnfirebase.com) then you only need to pass in your version of firebase as a prop (the firebase app is already initialized on the native side.)


### Provider Examples

```jsx
import * as firebase from "firebase/app";

import "firebase/auth";
import { FirebaseAuthProvider } from "@react-firebase/auth";

// And or
import { FirebaseDatabaseProvider } from "@react-firebase/database";
import "firebase/database";

// And or
import "firebase/firestore";
import { FirestoreProvider } from "@react-firebase/firestore";
```

```jsx
<FirebaseAuthProvider firebase={firebase} {...config}>
  <MyApp1 />
  <MyApp2 />
</FirebaseAuthProvider>
```

### Consumers

Every Module exports Consumer components that will consume and react (😅) to Firebase changes.

All Consumer Components expect their `children` prop to be a React Node or a sync function that returns a React Node. (library-specific examples below 👇)

#### Firebase Auth Consumers

##### `FirebaseAuthConsumer`

Anywhere inside your app component tree, add a FirebaseAuthConsumer to listen and update the ui when the user's auth status changes.

```jsx
<FirebaseAuthConsumer>
  {({ isSignedIn, user, providerId }) => {
    return isSigned ? (
      <pre style={{ height: 300, overflow: "auto" }}>
        {JSON.stringify({ isSignedIn, user, providerId }, null, 2)}
      </pre>
    ) : <div>Not signed in.</div>;
  }}
</FirebaseAuthConsumer>
```

##### [Auth API Reference](https://react-firebase-js.com/docs/react-firebase-auth/api)

#### Firebase Database Consumers

##### Read Data

###### `FirebaseDatabaseNode`

Anywhere inside your app component tree, add a `FirebaseDatabaseNode` to listen and update the ui when the data changes at the provided path.

```jsx
<FirebaseDatabaseNode path={"user_bookmarks/BOOKMARK_ID"}>
  {({ value, isLoading }) => {
    return (
      <pre>
        {JSON.stringify({ value, isLoading })}
      </pre>
    );
  }}
</FirebaseDatabaseNode>
```


You can also query your Firebase data by using all supported Firebase Realtime Database operators : 

```jsx
<FirebaseDatabaseNode path={"user_bookmarks/BOOKMARK_ID"} limitToFirst={10} orderByKey>
  {({ value, isLoading }) => {
    return (
      <pre>
        {JSON.stringify({ value, isLoading })}
      </pre>
    );
  }}
</FirebaseDatabaseNode>
```

[All supported props.](https://react-firebase-js.com/docs/react-firebase-realtime-database/api#firebasedatabasenode-props)

##### Write Data

###### `FirebaseDatabaseMutation` & `FirebaseDatabaseTransaction`

The mutation API is inspired by [apollo-graphql mutations](https://www.apollographql.com/docs/react/essentials/mutations.html).

The mutation components inject a `runMutation` or `runTransaction` prop, respectively to their children.

`FirebaseDatabaseMutation`, in addition to the `path` prop requires a mutation `type` prop that can be one of :

```typescript
"set" | "update" | "push";
```


###### FirebaseDatabaseMutation Example.</summary>

```jsx
<FirebaseDatabaseMutation path={collectionPath} type="push">
  {({ runMutation }) => (
    <button
      onClick={async () => {
        const { key } = await runMutation(testDocValue);
        if (key === null || typeof key === "undefined") return;
        this.setState(state => ({
          keys: [...state.keys, key]
        }));
      }}
    >
      add-node-with-generated-key
    </button>
  )}
</FirebaseDatabaseMutation>
```

###### FirebaseDatabaseTransaction Example.

```jsx
<FirebaseDatabaseTransaction path={path}>
  {({ runTransaction }) => {
    return (
      <div>
        <button
          onClick={() => {
            runTransaction({
              reducer: val => {
                if (val === null) {
                  return 1;
                } else {
                  return val + 1;
                }
              }
            }).then(() => {
              console.log("Ran transaction");
            });
          }}
        >
          Click me to run a transaction
        </button>
      </div>
    );
  }}
</FirebaseDatabaseTransaction>
```


- [FirebaseDatabaseMutation API](https://react-firebase-js.com/docs/react-firebase-realtime-database/api#firebasedatabasemutation-props)
- [FirebaseDatabaseTranasaction API](https://react-firebase-js.com/docs/react-firebase-realtime-database/api#firebasedatabasetransaction-props)

#### Firestore Database Consumers

##### Read Data with `FirestoreDocument` & `FirestoreCollection`

Anywhere inside your app component tree, add a `FirestoreDocument` or `FirestoreCollection` to listen to the data and update the ui when it changes.


###### `FirestoreDocument` Example.


```jsx
const s = v => JSON.stringify(v, null, 2);
const App = () => (
  <FirestoreDocument path={`/user_bookmarks/id`}>
    {({ value, path, isLoading }) => {
      return (
        <div>
          {value && <pre>{s(value)}</pre>}
          {path && <div>{path}</div>}
          <div>{isLoading}</div>
        </div>
      );
    }}
  </FirestoreDocument>
);
```


###### [`FirestoreDocument` API](https://react-firebase-js.com/docs/react-firestore-database/api#firestoredocument)


`FirestoreCollection` Example

```jsx
<FirestoreCollection path="/user_bookmarks/" limit={5}>
  {d => {
    return <pre>{s(d)}</pre>;
  }}
</FirestoreCollection>
```


###### [`FirestoreCollection` API](https://react-firebase-js.com/docs/react-firestore-database/api#firestorecollection)

##### Write Data with `FirestoreMutation` & `FirestoreTransaction` & `FirestoreBatchedWrite`

The mutation API is inspired by [apollo-graphql mutations](https://www.apollographql.com/docs/react/essentials/mutations.html).

The mutation components `FirestoreMutation` & `FirestoreTransaction` inject a `runMutation` or `runTransaction` prop, respectively to their children.

`FirestoreMutation` in addition to the `path` prop requires a mutation `type` prop that can be one of :

```typescript
"set" | "update" | "add";
```

The `BatchedWrite` exposes a different API because it behaves differently than writes and transactions, because it can run many updates before `committing` them.

It injects 2 props, `addMutationToBatch` and `commit`, to its children.

- `addMutationToBatch`

```typescript
type addMutationToBatch = (
  {
    path,
    value,
    type
  }: {
    path: string;
    value: any;
    type: "add" | "update" | "set" | "delete";
  }
) => void;
```

- `commit`

```typescript
type commit = () => Promise<void>;
```


##### `FirestoreMutation` Example

```jsx
<FirestoreProvider firebase={firebase} {...config}>
  <FirestoreMutation type="set" path={path}>
    {({ runMutation }) => {
      return (
        <div>
          <h2> Mutate state </h2>
          <button
            onClick={async () => {
              const mutationResult = await runMutation({
                nowOnCli: Date.now(),
                nowOnServer: firebase.firestore.FieldValue.serverTimestamp()
              });
              console.log("Ran mutation ", mutationResult);
            }}
          >
            Mutate Set
          </button>
        </div>
      );
    }}
  </FirestoreMutation>
</FirestoreProvider>
```


##### `FirestoreTranasaction` Example

```jsx
<FirestoreProvider firebase={firebase} {...config}>
  <FirestoreTransaction>
    {({ runTransaction }) => {
      return (
        <div>
          <button
            data-testid="test-set"
            onClick={async () => {
              await runTransaction(async ({ get, update }) => {
                const res = await get({
                  path
                });
                const data = res.data();
                if (typeof data === "undefined") return;
                await update(path, {
                  ...data,
                  a: isNaN(parseInt(data.a, 10)) ? 1 : data.a + 1
                });
              });
            }}
          >
            runTransaction
          </button>
        </div>
      );
    }}
  </FirestoreTransaction>
</FirestoreProvider>
```


##### `FirestoreBatchedWrite` Example

```jsx
<FirestoreBatchedWrite>
  {({ addMutationToBatch, commit }) => {
    return (
      <div>
        <h2>Batched write</h2>
        <button
          onClick={() => {
            console.log("adding to batch");
            addMutationToBatch({
              path,
              value: { [`a-value-${Date.now()}`]: Date.now() },
              type: "set"
            });
          }}
        >
          Add to batch
        </button>
        <button
          onClick={() => {
            console.log("committing to batch");
            commit().then(() => {
              console.log("Committed");
            });
          }}
        >
          Commit batch
        </button>
      </div>
    );
  }}
</FirestoreBatchedWrite>
```


## Resources

- [Source code](https://github.com/rakannimer/react-firebase)

- [Editable sandboxes](https://react-firebase-js.com/docs/try-it-out)

- [Verbose tutorial (WIP)](https://react-firebase-js.com/docs/guides/build-a-react-app-with-firebase-auth-and-realtime-database/setup-the-development-environment)

- [Bookmarking app example](https://github.com/rakannimer/react-firebase/tree/master/modules/tutorial-bookmarking-app)

- [React Native with Expo and Firebase Example](https://github.com/rakannimer/react-firebase/tree/master/react-native-examples/react-native-expo-firebase-example)

- [React Native Firebase Starter Example](https://github.com/rakannimer/react-firebase/tree/master/react-native-examples/react-native-firebase-starter)

## Related Work

- [re-base](https://github.com/tylermcginnis/re-base)
- [redux-firebase](https://github.com/prescottprue/redux-firebase)
- [react-firestore](https://github.com/green-arrow/react-firestore)
- Your Library ? Send me a DM or comment here to add it.


Thanks for making it to the end of the post ❤️ !

Here are a couple of additional resources just for you :

- [Generate connected JSON data](https://react-firebase-js.com/docs/generate-json-data)
- [Generate data in your Firebase Realtime Database](https://react-firebase-js.com/docs/generate-firebase-data)
- [Generate data in your Firebase Firestore Database](https://react-firebase-js.com/docs/generate-firestore-data)