Real-Time To-Do List Data Management in React using Redux-Saga and Socket

In the Era of Modern web application development, Many of the applications need real-time data management.

In this article, we will see how to develop a real-time To- Do application using React, Redux-Saga, and Socket.

First of all, let’s understand what are real-time web applications and why we need one.

What is Real-Time Web Application?

A real-time in the web application is transmitting data instantaneously without the need of client asking information every time. As a result, Changes in the data will be updated in all the clients connected in the system.it is achieved by using the WebSocket Protocol.

Http Vs WebSocket

Http is a request-response protocol in the client-server model. In Http, the client sends the request and get the response.

Whereas in WebSockets, Client sends a handshake first and the server responds to the handshake with an upgraded header for the upcoming requests.

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

In that way, the Client and Server send the message with low-latency between them. Also, Multiple clients can connect to a Socket and gets the data.

Example of Web Sockets

one of the examples of web sockets is a messaging platform, An application where users can communicate with each other. Example: WhatsApp.

When a Client makes a request to the server with WebSocket handshake, the Connection gets upgraded. Client and Server Communicate using WebSocket Protocol.

Implementation of WebSockets

Firstly, we will see how to implement the WebSocket in React Application using Redux-Saga and SocketIO(which a library built on top of web sockets).

I assume you are already familiar with React, Redux, and Redux-Saga. If you are not, I will suggest you read these articles before proceeding further with this tutorial.

React – Getting Started

Redux – Basics

Redux-Saga Tutorial

In this article, we will be building a real-time To- Do Application in React, Redux-Saga, and SocketIO.

Complete Source Code can be found Here

How does it work?

First of all, When Application Starts, React Component Dispatch an Action which is listened by a root Saga.

consequently, root Saga makes a Socket Connection with the Server and starts listening to specified socket room. As a result, when data gets added. redux-saga pushes the data to the Socket Room which is listened in server.

After that, The server takes the data from Socket and inserts the data to DB. After that, the server pushes the data again to another Socket Room.

The client takes the updated data and displays it in the list to all the clients who are active in the socket room.

First of all, create a folder called server and install express, mongoose, and socket.io with the following commands –

npm init --yes
npm install express socke.io mongoose

create a server.js file and add the following code. Basically, it creates an Express Server and connects with SocketIO. Once data is received in the socket room, it will insert into the database and push the updated data to another Socket Room.

server.js code
const express = require('express');

const mongoose = require('mongoose');
const http = require('http');

const app = express()

// const server = http.createServer(app);

const server = app.listen(4123);

const io = require('socket.io').listen(server);

const TodoModel = require('./TodoModel');

app.use(function(request, response, next) {
    response.header("Access-Control-Allow-Origin", "*");
    response.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
  });

mongoose.connect(`mongodb://localhost:27017/sockettodo`,{ useNewUrlParser : true })
    .then((err,res) => {

        console.log('mongodb connected successfully');

        io.sockets.on('connection',async (socket) => {

            console.log("Socket Connected");

            const todoCollection = await TodoModel.getTodos();

            io.sockets.emit('get-todos',{ todos : todoCollection });


            socket.on('insert-todo',async (data) => {

                await TodoModel.insertTodo(data);

                const todoCollection = await TodoModel.getTodos();
                console.log("todoCollection",todoCollection);
                io.sockets.emit('get-todos',{ todos : todoCollection  })
            })
        })

        

    })
    .catch(err => console.log(err))

create a file called TodoModel.js which contains the Todo Schema for Mongoose.

TodoModel.js code
const Mongoose = require('mongoose');


const todoSchema = new Mongoose.Schema({
    title : {
        type : String,
        required : true
    }
})

class Todo {


    static getById(id){

        return this.find({
            _id : Mongoose.mongo.ObjectID(id)
        }).exec();
    }

    static getTodos() {

        return this.find().exec();
    }

    static insertTodo(title){

        const todo = this({
            title
        })

        return todo.save();
    }

}

todoSchema.loadClass(Todo);

module.exports = Mongoose.model('Todo',todoSchema)

Subsequently, bootstrap the react app using create-react-app command and install redux, react-redux and socket.io-client with the following commands –

npx create-react-app client
npm install redux  redux-saga socket.io-client

file structure for React application will be something like the following one.

  • actionsthis folder contains all the redux action and Action Types of it.
  • componentsit contains components for the Application.
  • reducers – reducers maintains the state variables for an entire application.
  • sagas – Saga contains the Saga Middleware and Socket implementation part.

Socket and Saga Implementation

readTodo.js implements the socket connection and starts listening to the respective socket room.

readTodo.js code
import {take,put,call,fork} from 'redux-saga/effects'
import {eventChannel} from 'redux-saga'
import {
  GET_TODOS
  ,ADD_TODO_SUCCESS
  ,ADD_TODO_FAILRE
} from '../actions/actionTypes';

import  {
  onTodoAdded
} from '../actions/todoAction'
import {write} from './write'
import io from 'socket.io-client';

function connect() {
  const socket = io('http://localhost:4123/');
  return new Promise(resolve => {
    socket.on('connect', () => {
      resolve(socket);
      console.log("Socket connected");
    });
  });
}

function* read(socket) {
  const channel = yield call(subscribe, socket);
  while (true) {
    let action = yield take(channel);
    console.log("action",action);
    yield put(action);
  }
}

export function* subscribe(socket) {
  return new eventChannel(emit => {
    const update = todos => {
      console.log("listened data",todos);
      return  emit(onTodoAdded(todos));
    }
    console.log("socket listening on get-todos");
    socket.on('get-todos', update)
    return () => {}
  })
}

export function* flow() {
  yield take(GET_TODOS)
  const socket = yield call(connect)
  yield fork(read, socket)
  yield fork(write, socket)
}

Create a saga called write.js which will write the data to the socket room.

write.js code
import {channel} from 'redux-saga'
import {take,call,put,fork} from 'redux-saga/effects'
import {
  ADD_TODO
} from '../actions/actionTypes'

export function* write(socket) {

  while (true) {

    const {todo} = yield take(ADD_TODO)
    console.log("saga title",todo);
    socket.emit('insert-todo', todo.title)
  }
}

Demo

Summary

Hence, Real-time Data management is an important part of many web applications. implement it in a proper production application is a challenge. From this article, I hope you can understand how to implement it in a React Application using Redux, Redux-Saga, and SocketIO.

Complete Source Code can be found Here

SHARE ON
Real-Time To-Do List Data Management in React using Redux-Saga and Socket

You May Also Like

Leave a Reply

Your email address will not be published.