DEV Community

Cover image for Real-time app using React, Redux, Tailwind CSS & Firebase - Part 1
Emmanouil Liakos
Emmanouil Liakos

Posted on • Edited on • Originally published at blog.manos-liakos.dev

Real-time app using React, Redux, Tailwind CSS & Firebase - Part 1

NOTE: This series goes a bit unconventional, by not using any libraries or abstractions for Redux, following plain Flux architecture conventions. The recommended way of writing Redux is by using RTK (Redux Toolkit).

Hi y' all, this is part 1 of a multi-part series, in which we are going to build a real-time scrum voting app using some of the hottest frontend technologies! 😎

Stack

  • React & Redux for state management.
  • Tailwind CSS for quick and effortless styling.
  • Firebase Realtime Database for storage.

Requirements

The goal is to implement a web application that will be used by a remote scrum team, during their sprint planning session, to privately vote on the complexity score of a single story (task/feature to be implemented).

  • Full-fledged real-time implementation: All changes will happen in real-time and will be immediately visible to everyone.
  • Each client gets assigned a default random username when first visiting the app which he can also refresh.
  • Any participant can edit his/her username, as well as the feature-to-be-implemented title.
  • Any participant can vote and reveal all votes, effectively ending the session.
  • While votes are hidden, any participant that has voted gets a "Voted!" message next to his/her username.
  • When votes are revealed, users get reordered based on their votes. After that, anyone is able to reset the session, clearing all votes and resetting the feature title.

End result

You can check it live here.

The code is also here.

Phew, that seemed quite overwhelming 🤯. This project was part of a code challenge, so don't put the blame on me 😂 Anyway, let's get down to it.

Planning the application

One of the first things that I do when I start working on a front-end application is meticulously plan its architecture.

I visually divide the app into logical, self-isolated components with discrete functionality.

Then I search for reusable components which will either be placed in a commonmodule folder (in bigger projects) or will just be created with reusability in mind (dynamic, prop-based styling, etc.).

Wrappers are also reusable components which wrap other (child) components to provide them with extra functionality (visual or logical). They are officially called HOCs or Higher Order Components. I search for those kind of components, too. Imagine a Layout component which wraps our pages and provides them with static elements like Header, Footer, Menu, etc. or a Card component which wraps its children in a card-like element.

Next, I try to delegate possible state to each one of them (identifying stateful and stateless components), in case we are not using a centralized store for state management. In this case we will be using Redux, so only purely local state will be in-component.

Finally, I plan the app's folder structure as well as possible. Should the need to make changes down the road arise, especially if the app grows, a solid foundation is going to make for a resilient app.

Components

voting-app-components

By taking a look at the image above, one could easily distinguish between the following components:

Wrappers (HOCs)

  • Card (Used to wrap VotingArea & Users/Participants components)

Common/reusable

  • Button
  • Input

Normal

  • FeatureTitle (Based on Input component)
  • Heading

    • Username (Based on Input component)
  • Users

    • User
  • VotingArea

Stateful

All of our state is going to live in the Redux store, so no planning is going to take place in here 😊

Folder structure

Our app's code will live in src folder and is going to have the following structure:

├──src
   ├──__tests__
       ...test files...
   ├──common
      ...common functions used by many components...
   ├──components
      ...all of our components...
   ├──config
      ...configuration files...
   ├──containers
     ...I just left the App here as a container 😅...
   ├──firebase
     ...firebase service...
   ├──store
      ...our redux store...
      ├──actions
      ├──constants
      ├──reducers
   ├──utils
      ...helper functions...


Enter fullscreen mode Exit fullscreen mode

I hope it's mostly self-explaining. We are going to add some more folders in a later part, but for now, a bird's-eye view should do it.

Initialize application

To initialize our app, run:

npx create-react-app scrum-voting-app
Enter fullscreen mode Exit fullscreen mode

Install dependencies

Tailwind CSS

You can pretty much follow the official instructions here, there's no point in repeating them in this post.

Redux

We're going to use plain redux without any helpers (i.e. redux-toolkit). We are also going to use redux-thunk middleware to handle our async actions.

Run:

npm i redux react-redux redux-thunk
Enter fullscreen mode Exit fullscreen mode

Firebase

Here we need two libraries, firebase and react-redux-firebase. The first one is the Firebase SDK needed to connect to our database instance. The second one provides us with Redux bindings for Firebase in order to make our lives easier.

Run:

npm i firebase react-redux-firebase
Enter fullscreen mode Exit fullscreen mode

Modify files and structure

Create a folder called containers and move App.js and App.css in there and change the relative import in index.js accordingly:

import App from "./containers/App";
Enter fullscreen mode Exit fullscreen mode

Also change the logo import in App.js to avoid any errors:

import logo from "../logo.svg";
Enter fullscreen mode Exit fullscreen mode

Create the rest of the folders inside src, as seen in the Folder Structure section above. You can also delete App.test.js file or move it inside __tests__ folder.

Setting up Firebase

The next step, after we've finished drafting our application's blueprint, is to set up Firebase.

Firebase is a cloud JSON database which lets us store data in key-value pairs. Its Realtime Database flavor gives us the ability to synchronize every client using emitted events. All we have to do is utilize the API and create our handlers. Pretty cool, right? 🥳

Create an account

Go to https://console.firebase.google.com/ and login with your google account. Create a new project by clicking on "Add project". Type a name and optionally enable Analytics.

Create a database

Click on "Realtime Database" in the menu bar and then "Create Database". Choose a location and then "Start in test mode" to have our app publicly accessible to everyone. You can change this later if you want to add authentication and whatnot. Boom, you're up and running!

Adding a configuration file

Go to your project settings in Firebase console (Project Overview > Project Settings) and scroll down to "Your apps" section. Select our app and under "Firebase SDK snippet" choose "Config". This is our config object, copy it.

Create a file called firebase.js inside config folder and paste the config object and some additional code, likewise:

import firebase from "firebase/app";
import "firebase/database";
import "firebase/analytics";

// Configuration object copied from firebase console
const firebaseConfig = {
    apiKey,
    authDomain,
    databaseURL,
    projectId,
    storageBucket,
    messagingSenderId,
    appId,
    measurementId
};

// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();

export default firebase.database();
Enter fullscreen mode Exit fullscreen mode

Now we're ready to use our database.


That's it for this part, I hope you found it interesting.

Let me know if you catch any errors and stay tuned for part 2!

Top comments (3)

Collapse
 
samuelojes profile image
DGAME

Hoping for the next thanks man.

Collapse
 
mliakos profile image
Emmanouil Liakos

Glad you found it useful!

Collapse
 
rubenarushanyan profile image
Info Comment hidden by post author - thread only accessible via permalink
Ruben Arushanyan

Some comments have been hidden by the post's author - find out more