How to develop a Todo App in Next JS and Redis database from scratch
Muhammad Bilal
Full-stack Engineer Proficient in Next.js, React, TypeScript, TailwindCSS, React Native, Node.js,FastAPI, Postgresql and NoSQL databases.
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.
Pre-Requisites:
You need to have the following things installed on your system:
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.
You can either Sign Up using Github or using Google or by entering the form information.
2) Activate Free Tier Subscription
Then you will be redirected toward this page:
**NOTE**: For limited time.You will get $200 in credits using the coupon code TIGER200!??. So Signup today at Redis Enterprise to get started
3) Create A New Database.
?Until now we have activated our subscription. Now it's time to create new data.
4) Adding roles to our database.
The role will be saved named Admin with the specs we selected and you will see the following preview.
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.
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.
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.
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.
npx create-next-app todoappnextjsredis
Press enter after you write the command in the command prompt
cd todoappnextjsredis && npm run dev
2) Writing our front-end code for the todo app.
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.
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.
// 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.
//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.
/* 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?
// Components\Footer\index.jsx
const Footer = () => {
? ? return (
? ? ? ? <div className="footer">
? ? ? ? ? ? <div className="container">
? ? ? ? ? ? ? ? <div className="row">
? ? ? ? ? ? ? ? ? ? <div className="col-md-12">
? ? ? ? ? ? ? ? ? ? ? ? <p>Copyright © 2022 TodoAppNextJSRedis By <a target="_blank" >Muhammad Bilal</a></p>
? ? ? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? </div>
? ? ? ? </div>
? ? )
}
export default Footer;
/* 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
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;
/* 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
// 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
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
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
So type the following command and press enter.
npm i cors express nodemon redis-om
It will look like this in the cmd.
After the node modules are installed. Now it's time to write our backend code.
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'
});
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:
let endPoint = "Your copied endpoint";
let username = "Your username"
let password = "Your password";
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
npm start
1) Starting our Front End
npm run dev
and the project will be started on https://localhost:3000/.
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.
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.
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.
Now you can click on the database to view it. Will show up something like this.
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
Software Engineer || Fintech || Blockchain || B2C || B2B || SaaS || Enterprise Systems || DevOps
2 年Interesting piece.
Software Engineer @ INTECH | Computer Scientist ????
2 年Keep it up ????