43

I'm trying to integrate Firebase into my React app and after looking at various tutorials, I can't seem to find a consensus on where to put the firebase initialization code firebase.initializeApp(config).

My app's structure is this:

- app.js
- components
   |___Index.jsx
   |___Layout.jsx
   |___PageContent.jsx

Each file looks like the following

app.js

Does all the express setup with server-side rendering

Index.jsx

import React from 'react';
import Layout from './Layout.jsx';
import PageContent from './PageContent.jsx';
import './global.css';

class Index extends React.Component {
  render() {
    return (
        <Layout title={this.props.title}>
            <PageContent />
        </Layout>
    );
  }
}

export default Index;

PageContent.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import LandingPage from './components/Landing_Page/Landing.jsx';

class PageContent extends React.Component {
    render() {
        return (
            <LandingPage />
        );
    }
}

if (typeof window !== 'undefined') {
    ReactDOM.render(     
        <PageContent />,
        document.getElementById('root')        
    );
}

export default PageContent;

I need to make sure Firebase is available in every page of my website. Right now it is a single page app but eventually I'll be adding more.

Can anybody help me understand where I might put the database initialization code so that it is applied everywhere?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
MarksCode
  • 8,074
  • 15
  • 64
  • 133

3 Answers3

60

this is how I do it

create file Firebase.js next to app.js and put your initialization code

Firebase.js file

import * as firebase from 'firebase';

let config = {
    apiKey: "XXXXXXX",
    authDomain: "XXXXX",
    databaseURL: "XXXXX",
    projectId: "XXXXX",
    storageBucket: "XXXX",
    messagingSenderId: "XXXX"
};
firebase.initializeApp(config);

export default firebase;

and then import Firebase.js file every where you want to use it , for example

import React from 'react';    
import firebase from './../Firebase.js'     // <------  import firebase

class Test extends React.Component {

    componentDidMount(){
        firebase.database().ref().child("X").on('value' , {...});
    }

    render() {
        return (
            <h1>Hello</h1>
        );
    }
}

export default Test;
Ali Faris
  • 17,754
  • 10
  • 45
  • 70
  • 18
    Would this not initialize the firebase multiple times ? – Gaurav_soni Dec 13 '18 at 21:45
  • 8
    You can make the initialization like a singleton `export default !firebase.apps.length ? firebase.initializeApp(config) : firebase.app();` to avoid initializing it multiple times – Nitish Dhar Mar 03 '19 at 04:22
  • 2
    This seems like a good option, but only considering @NitishDhar's last comment to avoid multiple firebase app initializations. – Leonardo G. Jun 28 '19 at 16:07
  • 2
    Would someone mind explaining the above comment? Aren't ES6 modules only evaluated once? Thus the firebase app would only be initialised once, without the suggested singleton solution? – Sam Apr 10 '20 at 13:24
  • 24
    @NitishDhar's recommendation is unnecessary. ES6 modules are singletons with an instance being created for each file at the beginning of the runtime. Therefore `initialiseApp` will only be invoked once. happy days! I created a simple sandbox showing this: https://codesandbox.io/s/sharp-feather-9pf04?file=/src/index.js – Alex Mckay Jun 01 '20 at 03:10
  • If you're getting an error that says: `Attempted import error: 'initializeApp' is not exported from 'firebase' (imported as 'firebase')` see this: https://stackoverflow.com/questions/64545862/upgrade-to-firebase-js-8-0-0-attempted-import-error-app-is-not-exported-from – Lathryx Jun 26 '21 at 20:54
9

Create file with name firebase.js

import firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";

const firebaseConfig = {
  apiKey: 'AIzaXXXXXXXXXXXXXXXXXXXXXXX',
  authDomain: 'test-XXXX.firebaseapp.com',
  databaseURL: 'https://test-db.firebaseio.com',
  projectId: 'test-XXXX',
  storageBucket: 'test-bucket.appspot.com',
  messagingSenderId: 'XXXXXXX',
  appId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
};


firebase.initializeApp(firebaseConfig);
export const firebaseAuth = firebase.auth();
export const firestore = firebase.firestore()

Then use it as follows:

import { firebaseAuth } from 'firebase'
import SigninForm from 'signin.js'

const ModalSignIn = props => {

  const [email, setEmail] = useState()
  const [password, setPassword] = useState()

  const handleSubmit = e => {
    e.preventDefault()
    firebaseAuth
      .signInWithEmailAndPassword(email, password)
      .then(res => {
        console.log(res.user)
      })
      .catch(err => {
        const { code, message } = err
        console.log(code, message)
      })
  }

  return (<SigninForm/>)
Joma sim
  • 173
  • 1
  • 5
2

It seems that what you want is that firebase can be globally available to your react components.

It's the same question before using redux, how does react components consume the global state tree? Global variables? Come on, we'll know global variables are evil. React props? It seems very react but passing props down from root to the leaf components can't be fun.

Context API comes to rescue. You simply need firebase bindings for react just as redux/react-router did.

Assume you don't want to reinvent wheels,

and of course you can also build your own react firebase bindings through react context as just mentioned.

Allen
  • 4,431
  • 2
  • 27
  • 39
  • 2
    Using the Context API is very useful, however, I found that this caused a problem for me: I needed to access the Firebase.auth instance in my actions.js file where I used Redux-thunk to sign a user in and dispatch an action to update my Redux store with the UserID. Because the Context Provider passes the data to a wrapped component, this was not possible to implement as the actions.js file is not a component. I could not find any way to access the Provider directly. –  Sep 13 '19 at 15:45