How to develop a Todo App in Next JS and Redis database from scratch
Next JS and Redis Based TodoApp

How to develop a Todo App in Next JS and Redis database from scratch

Important Note:

This article was written 1 year ago and the genocide of palestinian people which is happening currently is strongly condemnable and can never be just justified at any stage.

Introduction:

This article is going to be the best place to start if you are a novice to Redis or Redis-JSON data store. Although?you should be familiar with some javascript and react js.

In this tutorial, we will be building a todo-app in the Redis database and next js from scratch. It's totally fine if you are not familiar with the Redis database. We will start from scratch. The final app will be able to perform CRUD operations using redisJSON and Next JS we will use as a front-end framework.

As a beginner when I started working with CRUD operations I remember that I struggled to find the right commands to implement CRUD operations in an app using a database. That is the reason I have planned to write a complete guide on working with Redis database crud operations using redisJSON.

Watch out for this video on why to choose Redis as your Database:

Live App and Source Code

This is a live preview of what we will be building at the end.

Live app

Source Code

Pre-Requisites:

You need to have the following things installed on your system:

  • NodeJS: Latest LTS version. I have used version v16.15.1
  • A Code Editor: Used VS Code while you are free to choose the editor of your own choice.
  • I assume you to be comfortable with javascript, Next JS(or React JS) and have at least six months of prior programming experience.

What is Redis?

Well, It's a no SQL database. But more precisely Redis is an in-memory key-value store that is often used as a cache to make traditional databases faster. However, it has evolved into a multimodel database capable of full-text search, graph relationships, AI workloads, and more.

What is RedisJSON?

RedisJSON is a Redis module that provides JSON support in Redis. RedisJSON lets your store, update, and retrieve JSON values in Redis just as you would with any other Redis data type. RedisJSON also works seamlessly with RediSearch to let you index and query your JSON documents. It is the best way to work with the Redis database.

Initial Setup

Note: I could have just asked you to go to the link to sign up to redis and setup database on your own and maybe beginners have struggled doing this that's why I dont want to see any one of you struggling in performing each step as I struggled in begenning and I am going to guide you step by step and in detail so none of you have confusion following me. If you think you can do that easily on your own. Just skip this section.

So let's get started.

1) SignUp for the Redis Cloud

?The fastest way to start using the Redis database is to utilize their free tier on Redis Enterprise Cloud.

You will see this page.

Redis Enterprise SignUp

You can either Sign Up using Github or using Google or by entering the form information.

2) Activate Free Tier Subscription

  • ?After successful signup, you will be redirected to this page.

Activate Subscription Page

  • Now you have to activate a free subscription plan. To do that. You have to click on the Activate Subscription Button As Shown below.

Activate Subscription By pressing Button

Then you will be redirected toward this page:

  • You can choose the free plan. Or Flexible or Annual Plan depending on your use case.
  • Then Choose AWS, Google, or Mircosoft Azure which prefer you. It's entirely your choice as shown below.

Choose What Prefers you

  • Then when you will scroll down. You can choose the data storage you require.30MB will be available for free. You can use the coupon code TIGER200!??.

**NOTE**: For limited time.You will get $200 in credits using the coupon code TIGER200!??. So Signup today at Redis Enterprise to get started

  • You can give your subscription any name you would like to give. For example, a free subscription is illustrated in the below image.

Give a subscription name and use a coupon code

  • Now Click on the create subscription to activate your subscription as shown below.

Press the create subscription button

  • Once you will click on the create subscription button your subscription will be activated and it will be shown in the subscription tab as shown in the image below.

After the subscription is activated

3) Create A New Database.

?Until now we have activated our subscription. Now it's time to create new data.

  • To create a new database click on this button by staying on the?page you were previously as shown in the below image.

Create New Subscription

  • Now you will be redirected to create a database wizard. Here give your database a name for example MyFirstRedisDatabase and in type choose Redis and select the modules RedisJSON and RediSearch as we will are going to use both in our app. This is illustrated below:

Give database a name and choose type and modules for database

  • As you scroll down to the next step keep everything as default as it is as shown below:

Keep defaults

  • Now to activate the database, click on the Activate database in the top right corner as shown below:

Click on Activate Database Button

  • Now a green tick will be displayed along with your database name showing that the database has been successfully initialized as shown below.

Database initialization complete

  • Also, you can see your database by pressing the Databases TAB on the top left corner as shown below.

Press Databases Tab

  • You will see your database activated and listed in the databases section as illustrated below:-

Databases section

4) Adding roles to our database.

  • For this navigate to the Data Access Control Tab by pressing the third option in the sidebar as shown below.

Navigate to Data Access Control

  • You will be navigated here:

Data Access Control

  • Now click on the tab named Roles as shown below.

Click on the roles tab

  • You will see this view.

Roles Add Page

  • Now click on the Add new role button as shown below.

click on the Add new role button

  • You will see this view.

Add new role page view

  • Now name the Role as an Admin and select the Subscription from the database dropdown as shown below.

Select Subscription from database

  • Then select Full Access from Redis acls drop down as shown below.

Click Full Access from dropdown]

  • Then press the tick button as shown below.

Click on the tick button to continue

  • Then Press the Save Role button in the bottom-right corner as illustrated below.

Click on the Save role button

The role will be saved named Admin with the specs we selected and you will see the following preview.

Saved role page

5) Adding users in Data Access Control.

?Now the last step is to add users so that the users you will add will be able to access the database and will be able to read, write and perform database operations depending on their access. We will now just give all permission to the user we will be adding. Let's get started.

  • Now press the Users tab as shown below.

click on the Users tab

  • Press the New user button as shown below.

Press the New user button

  • Now enter a username eg: bilal and select role as Admin and then enter password eg: Pass1233456789!. You can write your username and password and then press ok as shown below.

Press ok after entering the fields
Note:- Please do note that the username and password you are giving to a user you must remeber and write a password at your safe place because we will be using this username and password for getting the access to the redis database from our Node JS backend server code base.

  • After some time the status will be green means the user has been added successfully.

User Added Successfully

Congratulations on finishing this so far. Now, let's start creating our front-end part.

Developing the front end of the Todo App.

The front end of the todo app will be like this as illustrated in the below image.

Front End Todo App Next JS Redis

1) Creating a new next js application.

As I said earlier I will do everything from scratch nothing complex. I will do everything from the beginning like I am teaching this to a person who knows nothing about the subject matter. Let's create our next js application.

  • To create a next js app navigate to an empty folder. In this folder open the cmd. Just as shown below for windows.

Open CMD

  • Now remove the path and write here cmd and press enter. A terminal in the directory you are in will be opened. As shown below.

Write CMD to open terminal

  • The terminal will be opened like this for windows users as I am on windows while Linux users are good at self-learning they know how to open the terminal.

Terminal Opened

  • Now in the command prompt, type the following command.

npx create-next-app todoappnextjsredis              

Press enter after you write the command in the command prompt

  • It will show up like this in the command prompt. The template for creating the next app will be started for download.

Node modules started downloading

  • Now sit back and wait ?? until the node modules are installed and the template for creating the next app is downloaded.
  • Once installed in the terminal write the following command to navigate to the following js app directory and start the next js server.

cd todoappnextjsredis && npm run dev        

  • It will show up in the terminal like this.

Next js server started

2) Writing our front-end code for the todo app.

  • Open VS Code in the root of todoappnextjsredis folder.
  • You can enter this command in the command prompt in the root of the directory todoappnextjsredis.

code .        
open VS code command

  • Visual studio code in that directory will be opened. Now it's time to start writing front-end code.

Adding Mdbootstrap Library for styling

Mdbootstrap is a UI kit built with an aim to cut the time developers need to create their websites by taking all the best features from vanilla Bootstrap and enhancing them with a distinctive design from Google.

  • Navigate to this file pages\ _app.js.

Remove all the code and paste the following.

//pages\_app.js

import Head from 'next/head';

import Script from 'next/script';

import '../styles/globals.css'




function MyApp({ Component, pageProps }) {

?return <>

??<Head>

???<meta charSet="utf-8" />

???<meta name="description" content="A todo app built with Next JS,redis,Node JS and Express" />

???<meta name="keywords" content="TodoApp,NextJS,Redis,NodeJS,Express,Realtime" />

???<meta name="author" content="Muhammad-Bilal-7896" />

???<meta name="viewport" content="width=device-width, initial-scale=1" />

???<meta name="theme-color" content="#000000" />




???<title>NextJSRedisTodoApp</title>

??</Head>

??<Component {...pageProps} />

??<Script

???type="text/javascript"

???src="https://cdnjs.cloudflare.com/ajax/libs/mdb-ui-kit/3.5.0/mdb.min.js"

??></Script>

?</>

}

export default MyApp;        

As In the latest next js versions, the script tags are deprecated, and instead of script Script tags from next js are preferred.

  • Now navigate to this pages folder and create a new file named document.js and paste the following code after removing the previous one. This will be pages/_document.js

// pages/_document.js

import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {

??return (

????<Html>

??????<Head>

????????{/* Font Awesome */}

????????<link  rel="stylesheet" />

????????{/* Google Fonts */}

????????<link  rel="stylesheet" />

????????{/* MDB */}

????????<link  rel="stylesheet" />

????????{/* <!-- MDB --> */}

??????</Head>

??????<body>

????????<Main />

????????<NextScript />

??????</body>

????</Html>

??)

}        

Now Mdbootstrap is added successfully to our project.

Writing the front-end part.

  • Navigate to the file at this location pages\index.js.Rename the file index.js to index.jsx as it will allow better IntelliSense. Remove all the default code and paste the following code.

//pages\index.js

import { useEffect, useState } from "react";

import Head from 'next/head';

import Image from 'next/image';

//Importing Compoents

import Header from '../Components/Header';

import Footer from '../Components/Footer';

import TodoList from '../Components/Home/TodoList';


function Home() {

?const [addTodoValue, setAddTodoValue] = useState('');

?const [todoList, setTodoList] = useState([]);

?const [isCompleted, setIsCompleted] = useState(false);


?useEffect(() => {

??(async () => {

???const response = await fetch('https://localhost:8000/todo');

???const content = await response.json();

???setTodoList(content);

??})();

?}, []);


?useEffect(() => {

??console.log(`The TodoList is equal to : ${todoList}`);

?})


?const handleAddTodo = async (e) => {

??if (addTodoValue.length > 0) {

???e.preventDefault();

???const response = await fetch('https://localhost:8000/todo', {

????method: "POST",

????headers: { 'Content-Type': 'application/json' },

????body: JSON.stringify({

?????title: addTodoValue,

?????timeSubmitted: new Date().toLocaleString(),

?????completed: isCompleted

????})

???});


???const todo = await response.json();

???setTodoList([...todoList, todo]);

???alert(`The value will be added to TodoList: ${addTodoValue}`);

??} else {

???alert('Please enter a value to add to TodoList');

??}

?}


?return (

??<div>

???<Head>

????<title>TodoAppNextJSRedis</title>

???</Head>

???<Header />

???<div className={`container`}>

????<div className={`row`}>

?????<div className={`col-12`}>

??????<br />

??????<h1 className='text-center text-info'>NextJS & Redis Based Todo App</h1>

??????<form className='form_styling' onSubmit={handleAddTodo}>

???????<div className='d-flex'>

????????<div className='addItemInput'>

?????????<input className='form-control w-80' placeholder='Please Type Any Value to Add to the Todo' onChange={(e) => setAddTodoValue(e.target.value)} type="text" />

????????</div>

????????<button className='btn btn-dark' type="submit">Add Item</button>

???????</div>

??????</form>

??????<br />

??????<div className='todoListContainer'>

???????{

????????todoList.map((item, index) => {

?????????return (

??????????<div key={index}>

???????????<TodoList

????????????id={item.id}

????????????index={index}

????????????title={item.title}

????????????timeSubmitted={item.timeSubmitted}

????????????completed={item.completed}

????????????//Passing States

????????????todoList={todoList}

????????????setTodoList={setTodoList}

????????????isCompleted={isCompleted}

????????????setIsCompleted={setIsCompleted}

???????????/>

??????????</div>

?????????)

????????})

???????}

??????</div>

?????</div>

????</div>

???</div>

???<Footer />

??</div>

?)

}

export default Home;        

Now under the directory styles create a new folder named ContainerCss and then in ContainerCss folder create a file named Home.css.So this will be the path styles\ContainerCss\Home.css.Then write the following CSS code in that file.

/* styles\ContainerCss\Home.css */

.form_styling {
? ? width: 70%;
? ? background-color: #f2f2f2;
? ? padding: 20px;
? ? border-radius: 10px;
? ? margin: 0 auto;
}
.addItemInput {
? ? width: 85%;
? ? margin-right: 1%;
}
.todoListContainer{
? ? width: 70%;
? ? background-color: #dbd8f0;
? ? padding: 20px;
? ? border-radius: 10px;
? ? margin: 0 auto;
}        

Note: Currently if you will run the front end part. It will give errors because the components aren't created yet so follow me and you will be on track.

So Now let's create the components?

Creating Components

First, we will start with Header Component.

1) Header?

- First We will create a component named Header. So In the root create a Folder named Components and then in that folder create another folder called Header. Now create a file inside this folder called index.jsx.So the path will be Components\Header\index.jsx.Now write the following code in this file.

const Header = () => {
? ? return (
? ? ? ? <>
? ? ? ? ? ? {/* Navbar */}
? ? ? ? ? ? <nav className="navbar navbar-expand-lg navbar-light bg-light">
? ? ? ? ? ? ? ? {/* Container wrapper */}
? ? ? ? ? ? ? ? <div className="container-fluid">
? ? ? ? ? ? ? ? ? ? {/* Toggle button */}
? ? ? ? ? ? ? ? ? ? <button className="navbar-toggler" type="button" data-mdb-toggle="collapse" data-mdb-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
? ? ? ? ? ? ? ? ? ? ? ? <i className="fas fa-bars" />
? ? ? ? ? ? ? ? ? ? </button>
? ? ? ? ? ? ? ? ? ? {/* Collapsible wrapper */}
? ? ? ? ? ? ? ? ? ? <div className="collapse navbar-collapse" id="navbarSupportedContent">
? ? ? ? ? ? ? ? ? ? ? ? {/* Navbar brand */}
? ? ? ? ? ? ? ? ? ? ? ? <a className="navbar-brand mt-2 mt-lg-0" href="#">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <img src="/logo.png" height={45} title="Redis :) The most loved developers database." alt="Redis" loading="lazy" />
? ? ? ? ? ? ? ? ? ? ? ? </a>
? ? ? ? ? ? ? ? ? ? ? ? {/* Left links */}
? ? ? ? ? ? ? ? ? ? ? ? <ul className="navbar-nav fill me-auto mb-2 mb-lg-0">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <li className="nav-item">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="nav-link" href="#">Home</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <li className="nav-item">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="nav-link" target="_blank" title="Learn Redis" >Learn Redis</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <li className="nav-item">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="nav-link" target="_blank" title="Try Redis" >Try Redis</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <li className="nav-item">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="nav-link" target="_blank" title="Get Certified" >Get Certified</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <li className="nav-item">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="nav-link" target="_blank" title="Find Redis" href="https://www.dhirubhai.net/company/redisinc/">Find Redis</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <li className="nav-item">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="nav-link" target="_blank" title="Redis Users" >Redis Users</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <li className="nav-item">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="nav-link" target="_blank" title="Redis is one of the most loved database on stack overflow survey.Lets check" >Most Loved</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? </ul>
? ? ? ? ? ? ? ? ? ? ? ? {/* Left links */}
? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? {/* Collapsible wrapper */}
? ? ? ? ? ? ? ? ? ? {/* Right elements */}
? ? ? ? ? ? ? ? ? ? <div className="d-flex align-items-center">
? ? ? ? ? ? ? ? ? ? ? ? {/* Icon */}
? ? ? ? ? ? ? ? ? ? ? ? <a className="text-reset me-3" title="Learn With Redis University" target="_blank" >
? ? ? ? ? ? ? ? ? ? ? ? ? ? <img src="https://download.logo.wine/logo/Redis/Redis-Logo.wine.png" className="rounded-circle" height={50} alt="Muhammad Bilal" title="Muhammad Bilal" loading="lazy" />
? ? ? ? ? ? ? ? ? ? ? ? </a>
? ? ? ? ? ? ? ? ? ? ? ? {/* Avatar */}
? ? ? ? ? ? ? ? ? ? ? ? <div className="dropdown">
? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="dropdown-toggle d-flex align-items-center hidden-arrow" href="#" id="navbarDropdownMenuAvatar" role="button" data-mdb-toggle="dropdown" aria-expanded="false">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <img src="https://media-exp2.licdn.com/dms/image/C4D03AQEXk-Oc_il_Jw/profile-displayphoto-shrink_200_200/0/1624098249818?e=1661385600&v=beta&t=0-YbW3xzYac9E5BEJJ0ShrHJsDOfw2XXoVAyfSpDhmE" className="rounded-circle" height={25} alt="Muhammad Bilal" title="Muhammad Bilal" loading="lazy" />
? ? ? ? ? ? ? ? ? ? ? ? ? ? </a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? <ul className="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuAvatar">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="dropdown-item" title="Linkedin Profile" href="https://www.dhirubhai.net/in/muhammad-bilal-028843199/">Linkedin</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="dropdown-item" title="Github Profile" >Github</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <a className="dropdown-item" title="Email" href = "mailto:[email protected]">[email protected]</a>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </li>
? ? ? ? ? ? ? ? ? ? ? ? ? ? </ul>
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? {/* Right elements */}
? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? {/* Container wrapper */}
? ? ? ? ? ? </nav>
? ? ? ? ? ? {/* Navbar */}


? ? ? ? </>
? ? )
}
export default Header;        

Note: The header pages and links are totally up to you. Even the header is optional. What matters most is the front end and backend. Header and Footer are just optional.

  • Now create another file in the same Header folder named style.css.So its path will be Components\Header\style.css.Here write the following CSS snippet.

/* Components\Header\style.css */
.nav-link,
.nav-link:after,
.nav-link:before {
? ? transition: all .5s !important;
}

.nav-link {
? ? border-bottom: 1px solid transparent !important;
}

.nav-link:hover {
? ? color: rgb(236, 28, 56) !important;
? ? border-bottom: 1px solid rgb(236, 28, 56) !important;
? ? transition: 0.5s linear !important;
}        
Note : You have to keep in mind that all the css files are to be imported inside the app.js file but we will do that at the end after we have created all the css files.

2) Footer?

  • Now again inside Components Folder that is located at the root create a file named Footer. Now create a file inside this folder named index.jsx.Its relative path will be Components\Footer\index.jsx.Write the following code.

// Components\Footer\index.jsx
const Footer = () => {
? ? return (
? ? ? ? <div className="footer">
? ? ? ? ? ? <div className="container">
? ? ? ? ? ? ? ? <div className="row">
? ? ? ? ? ? ? ? ? ? <div className="col-md-12">
? ? ? ? ? ? ? ? ? ? ? ? <p>Copyright &copy; 2022 TodoAppNextJSRedis By <a target="_blank" >Muhammad Bilal</a></p>
? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? </div>
? ? ? ? </div>
? ? )
}
export default Footer;        

  • Now create a file named style.css in the same folder i.e Footer folder. The file path will be Components\Footer\style.css.Now write the following CSS snippet.

/* Components\Footer\style.css */
.footer {
? ? background-color: #f5f5f5;
? ? padding: 20px;
? ? margin-top: 20px;
? ? line-height: 50px;
? ? height: 80px;
? ? border:"1px solid #e5e5e5";
}        

Now it's time to create TodoList Component that will render our to-do list.

3) TodoList

  • Again inside the Components folder create a folder named Home. Inside Home folder create another folder named TodoList.Then inside TodoList folder create a file named index.jsx.Now the path of this file will be like this Components\Home\TodoList\index.jsx. Now write the following code inside this file.

import { useState } from "react";


const TodoList = (props) => {

? ? //Destructing the props object to get the props in variables
? ? const { id, index, title, completed, timeSubmitted, setTodoList, todoList, isCompleted, setIsCompleted } = props;


? ? const [isEdit, setIsEdit] = useState(false);


? ? const [editValue, setEditValue] = useState(title);


? ? //Methods
? ? const triggerUpdateToCloud = async (uniqueId, type) => {
? ? ? ? if (editValue !== "") {
? ? ? ? ? ? if (type === "markComplete") {
? ? ? ? ? ? ? ? // alert(`Triggering Update to Cloud with the value: ${editValue}`);
? ? ? ? ? ? ? ? await fetch(`https://localhost:8000/todo/${uniqueId}`, {
? ? ? ? ? ? ? ? ? ? method: "PUT",
? ? ? ? ? ? ? ? ? ? headers: { 'Content-Type': 'application/json' },
? ? ? ? ? ? ? ? ? ? body: JSON.stringify({
? ? ? ? ? ? ? ? ? ? ? ? completed: !completed,
? ? ? ? ? ? ? ? ? ? ? ? title: editValue,
? ? ? ? ? ? ? ? ? ? ? ? timeSubmitted: timeSubmitted
? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? let tempList = []
? ? ? ? ? ? ? ? for (let i = 0; i < todoList.length; i++) {
? ? ? ? ? ? ? ? ? ? let tempObj = todoList[i];
? ? ? ? ? ? ? ? ? ? if (todoList[i].id === uniqueId) {
? ? ? ? ? ? ? ? ? ? ? ? tempObj = { ...tempObj, completed: !completed }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? tempList.push(tempObj);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? setTodoList(tempList);
? ? ? ? ? ? ? ? setIsEdit(false);
? ? ? ? ? ? }
? ? ? ? ? ? else if (type === 'triggerUpdate') {
? ? ? ? ? ? ? ? const response = await fetch(`https://localhost:8000/todo/${uniqueId}`, {
? ? ? ? ? ? ? ? ? ? method: "PUT",
? ? ? ? ? ? ? ? ? ? headers: { 'Content-Type': 'application/json' },
? ? ? ? ? ? ? ? ? ? body: JSON.stringify({
? ? ? ? ? ? ? ? ? ? ? ? completed: completed,
? ? ? ? ? ? ? ? ? ? ? ? title: editValue,
? ? ? ? ? ? ? ? ? ? ? ? timeSubmitted: new Date().toLocaleString()
? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? let tempList = []
? ? ? ? ? ? ? ? for (let i = 0; i < todoList.length; i++) {
? ? ? ? ? ? ? ? ? ? let tempObj = todoList[i];
? ? ? ? ? ? ? ? ? ? if (todoList[i].id === uniqueId) {
? ? ? ? ? ? ? ? ? ? ? ? tempObj = { ...tempObj, title: editValue }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? tempList.push(tempObj);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? setTodoList(tempList);
? ? ? ? ? ? ? ? setIsEdit(false);
? ? ? ? ? ? }
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? console.warn("Please look at your function arguements.Make them correct.")
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? else {
? ? ? ? ? ? alert("Please enter a value to update");
? ? ? ? }
? ? }


? ? const deleteTodo = async uniqueId => {
? ? ? ? if (window.confirm('Are you sure you want to delete this task?')) {
? ? ? ? ? ? await fetch(`https://localhost:8000/todo/${uniqueId}`, {
? ? ? ? ? ? ? ? method: 'DELETE'
? ? ? ? ? ? });


? ? ? ? ? ? setTodoList(todoList.filter(t => t.id !== uniqueId));
? ? ? ? }
? ? }


? ? return (
? ? ? ? <div className="todoList">
? ? ? ? ? ? {(todoList.length !== 0) ? (
? ? ? ? ? ? ? ? <div>
? ? ? ? ? ? ? ? ? ? <div>
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? (isEdit) ? (
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <input type="text" value={editValue} onChange={(e) => setEditValue(e.target.value)} className="form-control" />
? ? ? ? ? ? ? ? ? ? ? ? ? ? ) : (
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (!completed) ? (
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <h3>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {index + 1}- {title}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </h3>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ) : (
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <h3 className="text-success">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <del>{index + 1}- {title}</del>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </h3>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ))
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? <div className="d-flex mt-4 justify-content-between">
? ? ? ? ? ? ? ? ? ? ? ? <h6 className="mt-2">{timeSubmitted}</h6>
? ? ? ? ? ? ? ? ? ? ? ? <div className="d-flex justify-content-between">
? ? ? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (!isEdit) ? (
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <button style={{ marginRight: "10px" }} className="btn btn-warning" onClick={() => setIsEdit(true)}>Edit</button>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ) : (
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <button style={{ marginRight: "10px" }} className="btn btn-success" onClick={() => triggerUpdateToCloud(id, "triggerUpdate")}>Update</button>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? )
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? <button style={{ marginRight: "10px" }} className="btn btn-danger" onClick={() => deleteTodo(id)}>Delete</button>
? ? ? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (!completed) ? (
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <button className="btn btn-success" onClick={() => triggerUpdateToCloud(id, "markComplete")}>Mark Complete</button>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ) : (
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <button className="btn btn-primary" onClick={() => triggerUpdateToCloud(id, "markComplete")}>Mark Incomplete</button>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? )
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ) : (
? ? ? ? ? ? ? ? <h3 className="text-center">No Tasks to Display</h3>
? ? ? ? ? ? )}
? ? ? ? </div>
? ? )
}
export default TodoList;        

  • While in the same folder TodoList create a file named style.css.So that its path will be like this Components\Home\TodoList\style.css.Now write the following code inside this file.

/* Components\Home\TodoList\style.css */

.todoList{
? ? width: 100%;
? ? height: 100%;
? ? background-color: #fff;
? ? border-radius: 5px;
? ? box-shadow: 0 0 5px #000;
? ? padding: 10px;
? ? overflow: hidden;
? ? margin-top: 5px;
}        

Importing our CSS files inside the app.js file

  • Now it's time to import all our CSS files so that styles could be applied to our app. For that Navigate to this file pages\ _app.js and add the following code after the previous imports.

// pages\ _app.js

//Importing Containers CSS Files
import '../styles/globals.css';
import "../styles/ContainerCss/Home.css";


//Importing Component CSS Files
import "../Components/Home/TodoList/style.css";
import "../Components/Footer/style.css";
import "../Components/Header/style.css";        

The complete _app.js would look like this.

// pages\ _app.js

import Head from 'next/head'
import Script from 'next/script';

//Importing Containers CSS Files
import '../styles/globals.css';
import "../styles/ContainerCss/Home.css";

//Importing Component CSS Files
import "../Components/Home/TodoList/style.css";
import "../Components/Footer/style.css";
import "../Components/Header/style.css";

function MyApp({ Component, pageProps }) {
? return <>
? ? <Head>
? ? ? <meta charSet="utf-8" />
? ? ? <meta name="description" content="A todo app built with Next JS,redis,Node JS and Express" />
? ? ? <meta name="keywords" content="TodoApp,NextJS,Redis,NodeJS,Express,Realtime" />
? ? ? <meta name="author" content="Muhammad-Bilal-7896" />
? ? ? <meta name="viewport" content="width=device-width, initial-scale=1" />
? ? ? <meta name="theme-color" content="#000000" />


? ? ? <title>NextJSRedisTodoApp</title>
? ? </Head>
? ? <Component {...pageProps} />
? ? <Script
? ? ? type="text/javascript"
? ? ? src="https://cdnjs.cloudflare.com/ajax/libs/mdb-ui-kit/3.5.0/mdb.min.js"
? ? ></Script>
? </>
}
export default MyApp;        

Now with this, our front end is completed and now it's time to write our backend code.

Writing the backend part:

Now you have to again come back to the folder from where we started. The folder where we entered the command to create our next js application. The below image shows that folder

No alt text provided for this image

Now you are not bound to write the backend in this folder. You can also write this in an empty folder. Just make sure the backend folder is separate from the front-end part. Don't write backend files in the same folder where we wrote our front end to avoid confusion.

Now create here a folder named backendtodoappnextjsredis. Then open cmd(or terminal if you are on Linux) and write the following command to initialize the empty js project.

npm init        
No alt text provided for this image

Choose default options for each value. Maybe you can write the author's name as your name and enter the description which is entirely your choice what to enter.

Note: It's important to choose an entry point as index.js file. It will be default. You just have to press enter while answering the questions.

In the end, it will ask you that Is this ok. You just have to press enter.

Now after this a file named package.json.Now we will modify this file for our convenience and use case.

Edit the package.json file according to the following settings. We have added the start command in the script and the type as "module".Other things like description, keywords, author, and license depend on your own choice. You would like to write the author's name as yours. So don't forget to do that. But remember don't edit scripts object of your own choice. You can but if you think you are qualified to do that then only.

?{
  "name": "backendtodoappnextjsredis",
? "version": "1.0.0",
? "description": "Backend based in redis database and nodejs and express",
? "main": "index.js",
? "type": "module",
? "scripts": {
? ? "start": "node src/index.js",
? ? "test": "echo \"Error: no test specified\" && exit 1"
? },
? "keywords": [
? ? "redis",
? ? "nodejs",
? ? "expressjs"
? ],
? "author": "Muhammad-Bilal-7896",
? "license": "MIT"
}
        

So Now in the root folder of the backend part where you have opened the cmd to generate JSON file. In the same cmd or terminal type the following command to install packages.

We will install the following packages

  • redis-om
  • cors
  • express
  • nodemon

So type the following command and press enter.

npm i cors express nodemon redis-om        

It will look like this in the cmd.

No alt text provided for this image

After the node modules are installed. Now it's time to write our backend code.

  • In the root of the backend, folder create a folder named src. Then inside this folder create another folder named schema. Now inside the schema folder create a file named task.schema.js.This file will contain our schema for the Redis backend. The relative path of this file from the root backend folder will be as follows: src\schema\task.schema.js. Add the following code to this file.

import {Entity, Schema} from "redis-om";


class Todo extends Entity {
? ? toJSON() {
? ? ? ? return {
? ? ? ? ? ? //Note: Remember here the entities you are adding you have to keep the pattern same everywhere.You can change add more entities or offcourse remove some of them
? ? ? ? ? ? id: this.entityId,
? ? ? ? ? ? title: this.title,
? ? ? ? ? ? timeSubmitted: this.timeSubmitted,
? ? ? ? ? ? completed: this.completed
? ? ? ? }
? ? }
}


//Note: Remember here the taskSchema you are adding you have to keep the pattern same everywhere.You can change add more entities or offcourse remove some of them
export const taskSchema = new Schema(Todo, {
? ? title: {
? ? ? ? type: 'string'
? ? },
? ? timeSubmitted:{
? ? ? ? type: 'string'
? ? },
? ? completed: {
? ? ? ? type: 'boolean'
? ? }
}, {
? ? dataStructure: 'JSON'
});        

  • Now in the src folder create a file named index.js.Add the following code to that file.

import express from 'express'
import cors from 'cors';
import { Client, Repository } from "redis-om";
import { taskSchema } from "./schema/task.schema.js";

const app = express();
app.use(express.json());
app.use(cors({
? ? origin: ['https://localhost:3000']
}));


//Note: I will explain how you can get your endpoint below.Add your username,endpoint and password here
let username = "bilal";
let password = "Your Password"
let endPoint = "redis-15666.c98.us-east-1-4.ec2.cloud.redislabs.com:15666";


const client = new Client();
await client.open(`redis://${username}:${password}@${endPoint}`);

// const taskRepository = new Repository(taskSchema, client);
const taskRepository = client.fetchRepository(taskSchema)


await taskRepository.dropIndex();
await taskRepository.createIndex();


app.get('/todo', async (req, res) => {
? ? res.send(await taskRepository.search().returnAll());
});


app.post('/todo', async (req, res) => {
? ? const todo = taskRepository.createEntity();


? ? todo.title = req.body.title;
? ? todo.timeSubmitted = req.body.timeSubmitted;
? ? todo.completed = req.body.completed;
? ? todo.id = await taskRepository.save(todo);


? ? res.send(todo);
});


app.put('/todo/:id', async (req, res) => {
? ? const todo = await taskRepository.fetch(req.params.id);


? ? //Update values
? ? todo.title = req.body.title;
? ? todo.completed = req.body.completed;
? ? todo.timeSubmitted = req.body.timeSubmitted;


? ? await taskRepository.save(todo);


? ? res.send(todo);
});


app.delete('/todo/:id', async (req, res) => {
? ? await taskRepository.remove(req.params.id);


? ? res.send(null);
});


app.listen(8000, () => {
? ? console.log("Redis Backend started on port 8000...");
});        

Adding your username, password, and endpoint:

  • Now on line no.12 as I said from here it's your job to add your username, password, and database endpoint. But don't worry I will explain every step. Now navigate to your Redis Cloud Console. Here log in and then you will be redirected to this page.

No alt text provided for this image

  • Now in the top left corner, a sidebar is located. Navigate to the databases tab and you will see this screen.

No alt text provided for this image

  • Now click the copy button located in the 5th column of the displayed information to copy your database endpoint. As shown below.

No alt text provided for this image

  • It will get you your database endpoint. You have to paste that endpoint on line no 15 of the most recent src\index.js code file. Like this

let endPoint = "Your copied endpoint";        

  • Now the username and password you can pick from the data access control tab. As I said earlier you have to remember and keep your password in a safe place. Because you cant view it.If you forget it. You can change that. Replace the username and password with your one on lines 13 and 14.

let username = "Your username"
let password = "Your password";        

  • You can get them from here and also if forget your password can change it from here.
  • Once you will hover your cursor over the password it will show you the option to delete and edit option. So if you want to change your password then click on edit one located on the right side beside the delete option.

No alt text provided for this image

Congratulations on going this so far. It means you are motivated to learn new technologies and concepts. Now after this we are completed with our backend part. Now it's time to run our application.

Running our TodoApp:-

Now it's time to finally start our project. First, we will start our backend server.

1) Starting Backend Server

  • To start that. Just Simply Navigate to the root of the backend folder and write the following command.

npm start        

  • Looks like this in the cmd.

No alt text provided for this image

  • A message: Redis Backend started on port 8000... will be displayed on the terminal if the backend is running without any errors.
  • You can take a look at the data in the database by going to the following API URL

https://localhost:8000/todo

1) Starting our Front End

  • Now navigate to the root of the front end next js project and start the project by opening the terminal or cmd in the root of the front end folder. Enter the following command to start our next js front end.

npm run dev        

and the project will be started on https://localhost:3000/.

No alt text provided for this image

If you followed all steps correctly you should be able to add a todo to the database and you should see that running.

A note on Redis Insight(Optional):

Redis Insight can be downloaded from here. Download Redis Insight

RedisInsight is a desktop manager that provides an intuitive and efficient GUI for Redis, allowing you to interact with your databases, monitor, and manage your data.

It will provide you with the ability to view and manage your Redis database directly from the Redis insight application.

Viewing our Redis database in RedisInsight.

  • Once you have downloaded and installed RedisInsight.You will see the following view:

No alt text provided for this image

  • Now click on the ADD REDIS DATABASE Button located in the center bottom. Now you will see this view.

No alt text provided for this image

  • Now choose Add Database Manually.
  • Then in the Host Input paste the copied endpoint from the Redis console. You can copy the endpoint once again from the Redis console as I previously guided you to do so. Once copied paste inside the Host input box as shown below.

No alt text provided for this image

The port and Database Alias will be automatically filled by RedisInsight.So don't worry about them. Also, enter your username and password as well.

No alt text provided for this image

Now on the bottom right corner Press the Add Redis Database button. The database will be added to your RedisInsight.

If the database has been successfully added it will show you a confirmation message.

No alt text provided for this image

Now you can click on the database to view it. Will show up something like this.

No alt text provided for this image

So that's it for now. I hope you followed all steps correctly. If you have any problem implementing this you can ask in the comment section I will answer your queries.

This post is in collaboration with Redis

Check out the following helpful links

Thanks for reading!

Regards

Muhammad Bilal

Tochukwu Adams

Software Engineer || Fintech || Blockchain || B2C || B2B || SaaS || Enterprise Systems || DevOps

2 年

Interesting piece.

Romaisa Ibrar

Software Engineer @ INTECH | Computer Scientist ????

2 年

Keep it up ????

要查看或添加评论,请登录

社区洞察

其他会员也浏览了