Create PWA ShoppingList with React and Firebase

C

Now it is time to use React to create PWA ShoppingList. In this tutorial you will learn how to use Firebase to store your mobile application data. You will create a shopping list application, which will store shopping items to Firebase.

Purpose and learning process

In this exercise you will learn the basics of the PWA development with React:

  • create a React app with PWA support
  • modify index.html
  • modify manifest.json
  • basic use of chrome development tools with PWA
  • save and load data from Firebase
  • use 3th party library to display shopping list data

Example screenshots and video

Demo app is a ShoppingList app, which stores shopping list items to Firebase.

Look example video from here: https://youtu.be/JyH5htuxpLU.

Setting Up Firebase

Firebase is Google’s mobile platform that helps you quickly develop high-quality apps and grow your business.

Go to the homepage of Firebase and click on the Get started button and Create a new ShoppingList project.

You can enable (or not) Google Analytics for your Firebase project. Google Analytics is a free and unlimited analytics solution that enables targeting, reporting and more in Firebase Crashlytics, Cloud Messaging, In-App Messaging, Remote Config, A/B Testing, Predictions and Cloud Functions.

Choose or create a Google Analytics account used with this app.

Your project should be now ready for development.

Note! This app can be done without Google Analytics.

Read more: https://firebase.google.com/.

Add a database

Configure Firebase realtime database for your ShoppingList App. Click on Cloud Firestore badge or select Database in left side menu. Click Create database button.

Select the “Start in test mode” option and click on the next button. Now you are developing your application, so you should start in test mode. Test mode lets anyone, with or without authentication, read and write to your database. Although this mode is good for developing and debugging, you should always change to production mode when you’re ready for production.

A final step is to specify Cloud Firestore location. You should select some location from Europe.

Finally your database is ready to use.

Add a sample data

Select your database and add a collection for a shoppinglist items. Select the + Add collection option, and create a name for collection. As highlighted in the tooltip, a collection is a set of documents, which contain a data. Use the items for creating a database of shoppinglist one item details.

And add a few sample data to the database. Use name as string and count as number fields. Click Add document to add more items to shoppinglist database.

Each shoppinglist items is a document in a database.

Create a new React project

Create a new React app with create-react-app @ GitHub. You’ll need to have Node 8.16.0 or Node 10.16.0 or later version on your local development machine (but it’s not required on the server).

Use npx, npm or Yarn to create your project.

npx create-react-app shoppinglist-app

Read more: Create React App.

Move web app to PWA

index.js

The production build has all the tools necessary to generate a first-class Progressive Web App, but the offline/cache-first behavior is opt-in only. By default, the build process will generate a service worker file, but it will not be registered, so it will not take control of your production web app.

In order to opt-in to the offline-first behavior, you should look for the following in their src/index.js file and use serviceWorker.register() to register Service Worker:

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.register();

As the comment states, switching serviceWorker.unregister() to serviceWorker.register() will opt you in to using the service worker and you now have a PWA.

Read more: Making a Progressive Web App.

index.html

Modify public/index.html to give a correct app name to your PWA. Replace correct <title>:

<title>Shopping List</title>

manifest.json

Modify public/manifest.json file to have correct name in short_name and name attributes:

"short_name": "Shopping List",
"name": "Shopping List",

You can use a default icons or create a new ones. if you want to replace the icons your app uses, remember place a new icons to public folder.

package.json

If you are planning to publish your app in some sub folder in your web server, then you should open package.json and add a following homepage attribute:

{
  "name": "shoppinglist-app",
  "homepage": "./",
  ...

Now static files are not looked from the webserver root. Of course you need to do this, if you are planning to publish your project to https://student.labranet.jamk.fi. You don’t have access to student web root, you only have access to your own folder in student.

Test

Start your development server and test that your app is working so far.

Give a command npm or yarn start

yarn start

And you should see your app running in localhost.

Firebase library

Add a Firebase library to your project with a following npm:

npm install firebase --save

Connect the firebase project

In Firebase ShoppingList project’s homepage, you will notice three circular icons. The first two will contain code that will help you connect Firebase project to an iOS and Android apps. The third one will have code that will help you connect the ShoppingList project to a web app.

Click on it, register your app.

Note apiKeyauthDomaindatabaseURLprojectIdstorageBucket
messagingSenderIdappId and measurementId values. These values are unique for each user’s each project.

Add a following code to your App.js. Remember change your own data here.

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

const firebaseConfig = {
  apiKey: "your-data-here",
  authDomain: "your-data-here",
  databaseURL: "your-data-here",
  projectId: "your-data-here",
  storageBucket: "your-data-here",
  messagingSenderId: "your-data-here",
  appId: "your-data-here",
  measurementId: "your-data-here"
};

Load sample ShoppingList items using React Hooks. Import useEffect and useState.

import React, { useEffect, useState } from 'react';

Modify your App.js to load ShoppingList items from Firebase. You can use useEffect to fetch data from the database.

function App() {
  // loading state
  const[loading, setLoading] = useState(true);
  // shopping list items state
  const[items, setItems] = useState([]);

  // load shopping list items
  useEffect(() => {
    const fetchData = async () => {
      // database
      const db = firebase.firestore();
      // data
      const data = await db.collection("items").get();
      // shopping list items: name, count and id
      const items = data.docs.map(doc => {
        return  { 
          name: doc.data().name, 
          count: doc.data().count, 
          id: doc.id 
        };
      });
      // set states
      setItems(items);
      setLoading(false);
    }
    // start loading data
    fetchData();
  },[]); // called only once

  // render loading... text
  if (loading) return (<p>Loading...</p>);

  // create shopping list items
  const sh_items = items.map( (item, index) => {
    return (<p key={index}>{item.name} {item.count}</p>);
  });

  // render shopping list
  return (
    <div className="App">
      {sh_items}
    </div>
  );
}

Test

Save and test your app. You should see your shopping list sample data in browser.

UI

Select for example Material-UI to create UI for ShoppingList app.

Install Material-UI’s source files via npm.

npm install @material-ui/core --save

Create UI with CardButtonTextField and Select components and use some styles. Card holds shopping list item TextField and delete Button components.

Add item to ShoppingList

Program add button to add a new item to ShoppingList database.

Add a new hooks to get item name and count from TextInput components and use onChange event in TextField‘s. Set default item name to "" and count to 1.

const[item, setItem] = useState("");
const[count, setCount] = useState(1);
onChange={e => setItem(e.target.value)}
onChange={e => setCount(e.target.value)

Add a new addItem function and call it from the add button’s onClick event. A new item will be created and added to the database. Database call will return added item document. This document id will be stored to shopping list item, so it can be deleted later.

// add a new item to data base and shopping list items
const addItem = async () => {
  // create a new shopping list item
  let newItem =  { name: item, count: count, id: '' };
  // add to database
  const db = firebase.firestore();
  let doc = await db.collection('items').add(newItem);
  // get added doc id and set id to newItem
  newItem.id = doc.id;
  // update states
  setItems( [...items,newItem]);
  setItem("");
  setCount(1);
}
onClick={() => addItem()}

Remove item from ShoppingList

Add a new removeItem function and call it from the shopping list items remove button’s onClick event. First delete item from database and then from the items state.

// delete item from database and UI
const deleteItem = async (item) => {
  // remove from db
  const db = firebase.firestore();
  db.collection('items').doc(item.id).delete();
  // delete from items state and update state
  let filteredArray = items.filter(collectionItem => collectionItem.id !== item.id);
  setItems(filteredArray);  
}
onClick={() => deleteItem(item)

Test

Test your app in localhost. It should work now.

Remember

  • test with mobile size – use ‘Toggle device tool’ in localhost
  • PWA test (publish first to your https-server)

Yes – this is not optimized PWA. You can learn how to optimize your PWA – for example in research assignment.

Build and publish

Create a new build and publish your files to server. Remember use https connection. Test your application in your mobile phone browser (chrome@Android, safari@iOS). It should work now as it is described at the beginning of this tutorial.

Final words

Firebase is execellent tool for developers.

Firebase Pros & Cons

  • Email & password, Google, Facebook, Github, etc… authentication
  • Realtime data
  • Ready-made api
  • Built in security at the data node level
  • File storage backed by Google Cloud Storage
  • Static file hosting
  • Treat data as streams to build highly scalable applications
  • etc…

Add comment

Pasi Manninen

Pasi Manninen

Pasi is a mobile and web application developer. Currently working as a senior lecturer in JAMK University of Applied Sciences. Pasi has programming experience over many decades and has taught dozens of courses since the 90's.

Recent Posts

Follow Me