This document describes how to build a simple todo application with React and Material UI. It discusses setting up the project structure with components, contexts, reducers and custom hooks to manage application state. Key aspects covered include using contexts to pass data between components, a reducer to manage todo data in local storage, and custom hooks for form inputs, toggling and local storage. The main components built are TodoApp, TodoList, TodoForm and Todo. This provides a fully functional todo app implementing modern React practices.
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
React Todo App with Material UI
1. Simple Todo Application With React and Material UI
Hey there everyone, hope you all are doing great. In today’s blog, we are going to create
a simple Todo Application With React and Material UI. We will build this simple React.Js
application and will store our information in the local storage. We will discuss every step
in this blog.
Before we start building this simple application, we assume you have some basic
understanding of JavaScript and the React.Js library. In this application, we will use the
best and most modern approach for our React application. We will separate our code
into smaller chunks so that you easily understand what it’s doing under the hood.
Application Structure of Simple Todo Application with React and Material UI
While building the application we will be keeping the best practices as a developer. We
will divide our app into smaller reusable components and one main file to host our
2. components. Our application will have three different reusable utility functionalities
folders. They are our context, reducers, and hooks. These folders will have their own
custom functions that will help us in creating logic for our to-do application.
Some Terms To Remember
● Components: Components in React are basically reusable pieces of code that we
can use anywhere in our application. Components can be anything like a reusable
Button, Card, Form, or any stuff that we think can be reused in our application.
The advantage of using the components in React is that it makes our application
more organized and human-friendly.
● Props: So if you are using JavaScript, then you have heard about the term
parameter or say arguments. They can be passed to a function as variable
holders of a function. Similarly, props or properties are the arguments or
parameters that we pass to React Components. Props are read-only. They can’t
mutate directly.
● State: State is the component variable. They hold certain values for our
components that can be changed later on during program execution. States can
be mutated with the help of hooks in React.
It’s Build Time
Now let us start building our application.
The first thing we will do is install Node.Js. Also kindly check the Node.Js version as
well. Now let’s create our project from scratch. But before let me mention that we will
use just React and Material UI.
Installation and Setup
Now let’s create a React App from scratch
npx create-react-app todoApp
3. or
yarn create react-app todoApp
Once the installation is complete, open this project folder with your favorite code editor.
In this case, we will use the VS Code. Also, let us quickly install the Material UI for our
project. Type the following command in the project root folder in your terminal.
Folder Structure
Our final folder structure will look like this.
node_modules
public
src
|
| --> context
| --> todos.context.js
| --> reducers
| --> todo.reducer.js
| --> hooks
| --> useInputState.js
| --> useLocalStorageReducer.js
| --> useToggleState.js
|
| --> App.js
| --> Todo.js
| --> TodoApp.js
| --> TodoList.js
| --> TodoForm.js
| --> EditTodoForm.js
| --> index.js
| --> index.css
4. Installing Materail UI
npm install @mui/material @emotion/react @emotion/styled
You can clean the files which you don’t want.
This application requires some logic for CRUD operation. So let’s create our contexts,
reducers, and custom hooks so that we can use them. These utility functions will allow
us to maintain our application state and help us to pass our data dynamically.
Globally Managing our States
Context
At first, we will build our todo context so that we can easily pass our props down the
order where it is necessary. Inside the context folder create a todos.context.js file. This
is the only application context we will create in this entire application.
import React, { createContext } from "react";
import { useLocalStorageReducer } from "../hooks/useLocalStorageReducer";
import todoReducer from "../reducers/todo.reducer";
const defaultTodos = [
{ id: 1, task: "Buy Milks and Bread", completed: false },
{ id: 2, task: "Release ladybugs into garden", completed: true },
6. If you look at the code above, you can see the context logic for our application. We are
passing some default to-do items. The todoReducer will allow us to manipulate the todo
form by creating a todo, editing the todo, and deleting them. Whereas the
useLocalStorageReducer allows us to store our pieces of information.
Hooks
In our custom hooks, we will be creating some custom hooks for managing our
application state that will keep changing at regular intervals. Our application will have
three custom hooks, i.e. ‘useLocalStorageReducer.js’, ‘useInputState.js’, and
‘useToggleState.js’. Each custom hook will have its own use case in our application.
Let us create our first custom hook useInputState.js
import { useState } from "react";
export default initialVal => {
const [value, setValue] = useState(initialVal);
const handleChange = e => {
setValue(e.target.value);
};
const reset = () => {
setValue("");
};
return [value, handleChange, reset];
};
7. The useInputState.js hook will allow the user to enter the form data of our application.
We can also reset the value of our form input.
Our next custom hook is the useLocalStorageReducer.js. This customs hook provides
us with the capability to store the new or updated to-do items in the local storage of our
web browser.
import { useReducer, useEffect } from "react";
function useLocalStorageReducer(key, defaultVal, reducer) {
const [state, dispatch] = useReducer(reducer, defaultVal, () => {
let value;
try {
value = JSON.parse(
window.localStorage.getItem(key) || String(defaultVal)
);
} catch (e) {
value = defaultVal;
}
return value;
});
useEffect(() => {
8. window.localStorage.setItem(key, JSON.stringify(state));
}, [key, state]);
return [state, dispatch];
}
export { useLocalStorageReducer };
Our last and final hook is useToggleState.js
jimport { useState } from "react";
function useToggle(initialVal = false) {
// call useState, "reserve piece of state"
const [state, setState] = useState(initialVal);
const toggle = () => {
setState(!state);
};
// return piece of state AND a function to toggle it
return [state, toggle];
}
9. export default useToggle;
The use of toggle custom hook is that it returns us with the piece of application state
and a function to toggle it.
Reducer
We will use todo.reducer.js it is for our reducer. Note that we are the UUID module to
create a unique id for each of our to-do lists. You can install the UUID with the following
command in your terminal. npm i uuid
import * as uuid from "uuid";
const reducer = (state, action) => {
switch (action.type) {
case "ADD":
return [...state, { id: uuid.v4(), task: action.task, completed: false }];
case "REMOVE":
return state.filter(todo => todo.id !== action.id);
case "TOGGLE":
return state.map(todo =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
);
case "EDIT":
10. return state.map(todo =>
todo.id === action.id ? { ...todo, task: action.newTask } : todo
);
default:
return state;
}
};
export default reducer;
Building The UI
Now our setup is complete, let’s create our React Component, i.e TodoApp.Js. This will
be our main application component whereas our other component will reside for UI
rendering.
import React from "react";
import TodoList from "./TodoList";
import TodoForm from "./TodoForm";
import Typography from "@material-ui/core/Typography";
11. import Paper from "@material-ui/core/Paper";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import Grid from "@material-ui/core/Grid";
import { TodosProvider } from "./context/todos.context";
function TodoApp() {
return (
<Paper
style={{
padding: 0,
margin: 0,
height: "100vh",
backgroundColor: "#fafafa"
}}
elevation={0}
>
<AppBar color='primary' position='static' style={{ height: "64px" }}>
13. This component will act as a container for our application. You can consider this to-do
component as a Parent element. Our component will display of todo application which
will render the other components.
Todo.js Component
import React, { useContext, memo } from "react";
import useToggleState from "./hooks/useToggleState";
import EditTodoForm from "./EditTodoForm";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItem";
import Checkbox from "@material-ui/core/Checkbox";
import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete";
import EditIcon from "@material-ui/icons/Edit";
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
import { DispatchContext } from "./context/todos.context";
function Todo({ id, task, completed }) {
const dispatch = useContext(DispatchContext);
const [isEditing, toggle] = useToggleState(false);
16. The Todo.js component is our main call to action component where most of the
application logic will reside.
Our next component will be todoList.js
import React, { useContext } from "react";
import Todo from "./Todo";
import Paper from "@material-ui/core/Paper";
import List from "@material-ui/core/List";
import Divider from "@material-ui/core/Divider";
import { TodosContext } from "./context/todos.context";
function TodoList() {
const todos = useContext(TodosContext);
if (todos.length)
return (
<Paper>
<List>
{todos.map((todo, i) => (
// To add a key to a fragment, we have to use the long-hand version
// rather than <> </>, we have to use <React.Fragment>
17. <React.Fragment key={i}>
<Todo {...todo} key={todo.id} />
{i < todos.length - 1 && <Divider />}
</React.Fragment>
))}
</List>
</Paper>
);
return null;
}
export default TodoList;
Our TodoList component will return the to-do list items that we create. Whenever we
create a new todo item, this react todo application component will render those new
lists.
TodoForm.js component
import React, { useContext } from "react";
import TextField from "@material-ui/core/TextField";
import Paper from "@material-ui/core/Paper";
19. margin="normal"
label="Add New Todo"
fullWidth
/>
</form>
</Paper>
);
}
export default TodoForm;
This component allows the user to enter values in the to-do form.
Our final todo component is EditTodoForm.js
import React, { useContext } from "react";
import useInputState from "./hooks/useInputState";
import TextField from "@material-ui/core/TextField";
import { DispatchContext } from "./context/todos.context";
function EditTodoForm({ id, task, toggleEditForm }) {
const dispatch = useContext(DispatchContext);
21. autoFocus
/>
</form>
);
}
export default EditTodoForm;
This component will allow us to edit the to-do form.
Now at last we will display all the application UI in our main App.js file.
import React from "react";
import TodoApp from "./TodoApp";
function App() {
return <TodoApp />;
}
export default App;
And that’s it, guys. Here we have a fully functional React Todo Application with modern
React practices. And hope you guys will like this simple react application.
How To Run This Project
It’s very simple to run this project. Just follow the steps.
22. ● Make sure you have node.js installed on your system if not then download it first.
● After that, you open the project in your favorite code editor(VS Code is
preferable).
● If you are using Vs Code then, simply open the code editor and open your project.
○ Then open a new terminal (ctrl + shift + ~ ==> will open a new
terminal).
○ run this command `npm install`
○ then `npm start
● If you want to directly run without a code editor, then follow these steps:
○ open a terminal(command prompt or git bash)
○ goto your project root directory(cd folder name)
○ then again type `npm install` and then after installation `npm start`
In case npm gives you any kind of error then you can run the project with the Yarn
package manager instead. Follow these steps:
● Open your windows terminal
● the type `npm i –global yarn`. This will install your yarn package manager
globally.
● After the installation, repeat the same commands from the above but this time
uses yarn instead of npm.
● `yarn install` and then to start `yarn start`.
Conclusion
That’s it for this tutorial and blog. Here in this article, we learned about building a simple
React Todo List application from scratch with custom React Hooks. The application
uses the Material UI for the design. Hope you will like this simple tutorial.