The release of version 9 of the Firebase Web SDK includes a breakthrough change in the way users are managed and databases are queried. Code written in Firebase V8.x will have errors when used in V9.x, which will require refactoring.

In this article, we’ll learn how to refactor a React application that uses the Firebase Web SDK V8.x to v9.x, also known as the modular Web SDK. For our example, we’ll take an Amazon clone built with V8.x and refactor it to V9.x.

The premise condition

To follow this tutorial, you should be familiar with React and Firebase V8.x, and you should also have Node.js installed on your machine.

This section describes the Firebase V9.x Web SDK

The new Web SDK does away with the namespace approach used in version 8. Instead, it uses an optimized modular format to eliminate unused code, such as tree shaking, which greatly reduces the size of JavaScript bindings.

The transition to a modular approach introduced some disruptive changes that made the new libraries backward incompatible and caused code used in V8.x to be corrupted in the new Firebase V9.x SDK.

The code below shows some of the disruptive changes introduced in the new library.

// VERSION 8
import firebase from 'firebase/app';
import 'firebase/auth'; 

firebase.initializeApp();
const auth = firebase.auth();

auth.onAuthStateChanged(user => { 
  // Check for user status
});


// VERSION 9 EQUIVALENT
import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';

const firebaseApp = initializeApp();
const auth = getAuth(firebaseApp);

onAuthStateChanged(auth, user => {
  // Check for user status
});

Copy the code

The two code samples above both monitor a user state. Although both use similar lines of code, in V9.x we did not import the Firebase namespace or the Firebase/Auth side effect, which enhances the authentication service into the Firebase namespace, but instead imported and used a single function.

These changes take advantage of the code-elimination features of modern JavaScript tools like Webpack and Rollup.

For example, the v8.x code above includes the following code snippet.

auth.onAuthStateChanged(user => { 
  // Check for user status
});

Copy the code

Auth is a namespace and a service that contains the onAuthStateChanged method. Also contains the namespace as signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut, these methods are not used by the code. When we bundle the entire code, these unused methods are also included in the bundle, resulting in an increase in relative size.

Although bundlers like Webpack and Rollup can be used to eliminate unused code, they will have no effect because of the namespace approach. Solving this problem is one of the main goals of reshaping the API surface to take a modular form. To learn more about the reasons behind the changes to the new library, check out the Official Firebase blog.

Firebase compatibility library

The new SDK also includes a compatibility library with familiar API surfaces, which is fully compatible with V8.x. Compatibility libraries allow us to use both old and new apis in the same code base, allowing us to gradually refactor our application without breaking it. We can use the compatibility library by making some adjustments to the import path, as shown below.

import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';

Copy the code

We’ll take advantage of this library when we refactor our Amazon clone application.

Firebase Web SDK V9.x benefits

In short, Firebase Web SDK V9.x offers reduced size and increased overall performance. The new Web SDK provides a faster Web experience by leveraging code elimination features with JavaScript tools like Webpack and Rollup. The new SDK is said to be about 80% smaller than its predecessor due to its new modular shape, according to the official Firebase Twitter account.

Set up our React app for refactoring

Now that we’re familiar with the new SDK, let’s learn how to refactor our V8.x application. The Amazon clone application we’ll use in this section is an e-commerce application built using Firebase and Strapi.

In our application, we use Firebase to add some functions, such as Firebase authentication to manage user identity, and Cloud Firestore to store products purchased by authenticated users. We use Strapi to handle payment for products purchased on the application. Finally, we created an API with express.js that responds with Strapi client secrets to customers about to purchase products with Firebase cloud capabilities.

You can visit the deployed version of the site, which looks like the image below.

Feel free to play around with the app to better understand what we’re working on in this article.

Set up amazon’s clone app

Before we start coding, let’s first clone the repo from GitHub and install the necessary NPM packages. Open your terminal and navigate to the folder where you want to store the React application. Add the following command.

$ git clone https://github.com/Tammibriggs/Amazon-clone-FirebaseV8.git
$ cd Amazon-clone-FirebaseV8

Copy the code

Now that we have successfully cloned the repo, we need to change the Firebase version in the package.json file to V9.x before installing the package.

In the root directory, open package.json and replace “Firebase “: “8.10.0” in the dependent object with” Firebase “: “9.2.0”. Now, let’s install our application’s dependencies by running the following command on the terminal.

$ npm install 
$ cd functions
$ npm install 

Copy the code

Even though we have all of our application’s dependencies set up and installed, if we try to run the application with NPM start, it will get an error. To avoid this, we need to fix disruptive changes to our application, which we will soon do.

Structure of the React application

The SRC directory structure for our application is as follows, but we’ve removed all the style files to make it look shorter.

SRC ┣ Checkout service ┣ checkoutproduct.js ┃ ┣ checkoutproduct.js ┃ outside subtotal.js ┣ Header ┃ outside header.js service Home ┃ outside ull Product. Js ┣ Login multidisciplinary login.js ┣ Orders ┃ ┣ order.js ┃ multidisciplinary orders.js ┣ Payment ┃ disintegration disintegration disintegration disintegration disintegration disintegration disintegration disintegration disintegration disintegration disintegration disintegration disintegration disintegration Firebase.js ┣ index.js ┣ reducer. Js ┣ reportwebvitals.js L stateprovider.jsCopy the code

We will only work with files that use Firebase services, Firebase, app.js, header. js, login. js, payment.js, and Orders.js.

Refactoring amazon’s clone files into a modular approach

Let’s update to v9.x’s Compat library to help us gradually migrate to a modular approach until we no longer need the Compat library.

The upgrade process follows a repeating pattern; First, it refactors the code for a single service, such as authentication, to a modular style, and then removes the compat library for that service.

Update import to 9.x compat library

Go to the firebase.js file in the SRC directory and modify the v8.x import to look like the following code.

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

Copy the code

With just a few changes, we updated the application to V9.x Compat. Now we can start our application with NPM start without any errors. We should also launch the Firebase function locally to expose the API that gets customer secrets from Strapi.

On your terminal, change to the functions directory and run the following command to start the function.

 $ firebase emulators:start

Copy the code

Refactoring authentication code

On login. js, app. js, and header. js, we use the Firebase authentication service. First, let’s reconstruct the Login. Js files in the code, and here we created to create user function, and through the FirebasecreateUserWithEmailAndPassword and signInWithEmailAndPassword method to sign them. When we scan the login. js file, we see the v8.x code below.

// src/Login/Login.js
const signIn = e => {
    ...
    // signIn an existing user with email and password
    auth
      .signInWithEmailAndPassword(email, password)
      ....
  }

  const regiter = e => {
    ...
    // Create a new user with email and password using firebase
    auth
      .createUserWithEmailAndPassword(email, password)
      ....
  }  

Copy the code

In order to follow the modular approach, we will import from the auth module signInWithEmailAndPassword and createUserWithEmailAndPassword method, and then update the code. The refactored version will look like the code below.

// src/Login/Login.js
import {signInWithEmailAndPassword, createUserWithEmailAndPassword} from 'firebase/auth'

...
const signIn = e => {
  ...
  // signIn an existing user with email and password
  signInWithEmailAndPassword(auth, email, password)
  ...
}
const regiter = e => {
  ...
  // Create a new user with email and password using firebase
  createUserWithEmailAndPassword(auth, email, password)
  ...
}  

Copy the code

Now, let’s refactor the app.js and header. js files. In the app.js file, we use the onAuthStateChanged method to monitor changes in user login status.

// src/App.js useEffect(() => { auth.onAuthStateChanged(authUser => { ... }}), [])Copy the code

Modular V9.x of the above code looks like the following.

// src/App.js import {onAuthStateChanged} from 'firebase/auth' ... useEffect(() => { onAuthStateChanged(auth, authUser => { ... }}), [])Copy the code

In the header. js file, we use the signOut method to check out the authenticated user.

// src/Header/Header.js
const handleAuthentication = () => {
  ...
     auth.signOut()
  ...
}

Copy the code

Update the code above to look like the code snippet below.

// src/Header/Header.js
import {signOut} from 'firebase/auth'
...
const handleAuthentication = () => {
  ...
    signOut(auth)
  ...
}

Copy the code

Now that we’re done refactoring all of our authentication code, it’s time to remove the Compat library to gain our scale advantage. In the firebase.js file, replace import ‘Firebase /compat/auth’ and const Auth = Firebaseapp.auth () with the following.

import {getAuth} from 'firebase/auth'
...
const auth = getAuth(firebaseApp)

Copy the code

Refactor the Cloud Firestore code

The process of refactoring Cloud Firestore code is similar to what we just did with the authentication code. We will work with the payment.js and orders.js files. In payment.js, we use Firestore to store data about users who pay for products on the site. In payment.js, we’ll find the v8.x code below.

// src/Payment/Payment.js ... db .collection('users') .doc(user? .uid) .collection('orders') .doc(paymentIntent.id) .set({ basket: basket, amount: paymentIntent.amount, created: paymentIntent.created }) ...Copy the code

To refactor the code, we first import the necessary functions and then update the rest of the code. The v9.x of the code above looks like this.

// src/Payment/Payment.js import {doc, setDoc} from 'firebase/firestore' ... const ref = doc(db, 'users', user? .uid, 'orders', paymentIntent.id) setDoc(ref, { basket: basket, amount: paymentIntent.amount, created: paymentIntent.created }) ...Copy the code

In the orders.js file, we use the onSnapshot method to get real-time updates of the data in Firestore. The code for V9.x looks like this.

// src/Orders/Orders.js .... db .collection('users') .doc(user? .uid) .collection('orders') .orderBy('created', 'desc') .onSnapshot(snapshot => { setOrders(snapshot.docs.map(doc => ({ id: doc.id, data: doc.data() }))) }) ...Copy the code

The corresponding code for v9.x is as follows.

import {query, collection, onSnapshot, orderBy} from 'firebase/firestore'

...
const orderedOrders = query(ref, orderBy('created', 'desc'))
onSnapshot(orderedOrders, snapshot => {
     setOrders(snapshot.docs.map(doc => ({
       id: doc.id,
       data: doc.data()
     })))
  })
...

Copy the code

Now that we have completed the refactoring of all Cloud Firestore code, let’s remove the Compat library. In firebase, js file, use the following code to replace the import ‘firebase/compat/firestore and const db = firebaseApp firestore ().

import { getFirestore } from "firebase/firestore"; . const db = getFirestore(firebaseApp) ...Copy the code

Update the initialization code

The final step in upgrading our Amazon clone application to the new modular V9.x syntax is to update the initialization code. In the firebase.js file, replace import Firebase from ‘firebase/compat/app’ with the following function; And constfirebaseApp = FireBase. InitializeApp (firebaseConfig).

import { initializeApp } from "firebase/app"
...
const firebaseApp = initializeApp(firebaseConfig)
...

Copy the code

We have now successfully upgraded our application to follow the new V9.x modular format.

conclusion

The new Firebase V9.x SDK offers a faster web experience than its predecessor, V8.x, due to its modular format. This tutorial introduces the new SDK and explains how to use its compact library to reflect a React application. You should be able to follow these steps to upgrade your own application to the latest version.

If you’re still having trouble refactoring the React application, be sure to check out the Firebase support community below.

  • Slack community
  • StackOverflow
  • Google groups

The postRefactor a React app with the new Firebase v9.x Web SDKappeared first onLogRocket Blog.