How to use firebase auth and Cloud Firestore from different components as a single firebase App

You use different instances of Firebase in App and Component.

// firebaseApp.js
import firebase from 'firebase'
const config = {
    apiKey: "...",
    authDomain: "...",
    databaseURL: "....",
    projectId: "...",
    messagingSenderId: "..."
};
firebase.initializeApp(config);
export default firebase;

Than you can import firebase from firebaseApp.js and use it. More details here


Make a file firebaseConfig.js in src/firebase directory for firebase configuration:

import firebase from 'firebase/app'; // doing import firebase from 'firebase' or import * as firebase from firebase is not good practice. 
import 'firebase/auth';
import 'firebase/firestore';

// Initialize Firebase
let config = {
    apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
    authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
    databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
    projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
    storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
    messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
};
firebase.initializeApp(config);

const auth = firebase.auth();
const db = firebase.firestore();

const googleAuthProvider = new firebase.auth.GoogleAuthProvider();
const emailAuthProvider = new firebase.auth.EmailAuthProvider();

export { auth, firebase, db, googleAuthProvider, emailAuthProvider };

All you have to do in Component.js is:

import { db } from './firebase/firebaseConfig.js'; // Assuming Component.js is in the src folder

Store the api keys in a .env file in the root folder of the project (the parent of src):

REACT_APP_FIREBASE_API_KEY=<api-key>
REACT_APP_FIREBASE_AUTH_DOMAIN=<auth-domain>
REACT_APP_FIREBASE_DATABASE_URL=<db-url>
REACT_APP_FIREBASE_PROJECT_ID=<proj-name>
REACT_APP_FIREBASE_STORAGE_BUCKET=<storage-bucket>
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=<message-sender-id>

You can use a context as you said or redux (using a middleware to initialize, and global state to keep the db):

// Main (for example index.js)
<FirebaseContext.Provider value={new Firebase()}>
    <App />
</FirebaseContext.Provider>

Firebase.js:

import app from 'firebase/app'
import 'firebase/firestore'

const config = {
  apiKey: process.env.API_KEY,
  databaseURL: process.env.DATABASE_URL,
  projectId: process.env.PROJECT_ID,
  storageBucket: process.env.STORAGE_BUCKET
}

export default class Firebase {
  constructor() {
    app.initializeApp(config)

    // Firebase APIs
    this._db = app.firestore()
  }

  // DB data API
  data = () => this._db.collection('yourdata')

  ...
}

FirebaseContext.js:

import React from 'react'

const FirebaseContext = React.createContext(null)

export const withFirebase = Component => props => (
  <FirebaseContext.Consumer>
    {firebase => <Component {...props} firebase={firebase} />}
  </FirebaseContext.Consumer>
)

Then you can use withFirebase in your container components:

class YourContainerComponent extends React.PureComponent {
  state = {
    data: null,
    loading: false
  }

  componentDidMount() {
    this._onListenForMessages()
  }

  _onListenForMessages = () => {
    this.setState({ loading: true }, () => {
      this.unsubscribe = this.props.firebase
        .data()
        .limit(10)
        .onSnapshot(snapshot => {
          if (snapshot.size) {
            let data = []
            snapshot.forEach(doc =>
              data.push({ ...doc.data(), uid: doc.id })
            )
            this.setState({
              data,
              loading: false
            })
          } else {
            this.setState({ data: null, loading: false })
          }
        })
     })
   })
  }

  componentWillUnmount() {
    if (this._unsubscribe) {
      this._unsubscribe()
    }
  }
}


export default withFirebase(YourContainerComponent)

You can see the whole code here: https://github.com/the-road-to-react-with-firebase/react-firestore-authentication and a tutorial here: https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/

If you implement it using redux, and redux-thunk you can isolate all firebase stuff in middleware, actions, and reducers (you can take ideas and sample here: https://github.com/Canner/redux-firebase-middleware); and keep the business logic in your components so they do not need to know how your data collections are stored and managed. The components should know only about states and actions.