What is React?
React is a javaScript
library that use to build our user interface for applications.
What is useReducer
useReducer
is a react hook that is used to implement our complex state of applications.
In this simple todo app I have used react with typescript template
Step 1:
First of all, create a project called todo using
create-react-app
npx create-react-app todo --template typescript
After creating the projectcd
to todo folder then run
npm start
oryarn start
Step 2:
- Create two folder called containers , components
- Create a file called Todos.tsx in containers
- Import Todos.tsx file in App.tsx and use it
import * as React from "react";
import Todos from "./container/Todos";
const App: React.FC = () => {
return <Todos />;
};
export default App;
- Create an interface that will represent the blueprint of a todo item in Todos.tsx file
export interface TodosProps {
id: string;
todoName: string;
isComplete: boolean;
}
- Create interfaces for various activities of the app like add todo item, remove todo item and toggle the todo to check that todo item is completed or not
interface AddTodoAction {
type: "ADD_TODO";
payload: { name: string };
}
interface ModifyTodoAction {
type: "TOGGLE_TODO" | "DELETE_TODO";
payload: { id: string };
}
- action type
export type TodoAction = AddTodoAction | ModifyTodoAction
- Create a reducer function called todoReducer that is used with useReducer to control the state with action.
const todoReducer = (todos: Array<TodosProps>, action: TodoAction) => {
switch (action.type) {
case "ADD_TODO":
return [...todos, newTodo(action.payload.name)];
case "TOGGLE_TODO":
return todos.map((todo) => {
if (todo.id === action.payload.id) {
return { ...todo, isComplete: !todo.isComplete };
}
return todo;
});
case "DELETE_TODO":
return todos.filter((todo) => todo.id !== action.payload.id);
default:
return todos;
}
};
- Create a new todo item structure with this function
const newTodo = (todoName: string): TodosProps => {
return { id: uuidv4(), todoName: todoName, isComplete: false };
};
- Todos.tsx
import * as React from "react";
import { useReducer } from "react";
import { v4 as uuidv4 } from "uuid";
import Todo from "../components/Todo";
import TodoInput from "../components/TodoInput";
export interface TodosProps {
id: string;
todoName: string;
isComplete: boolean;
}
interface AddTodoAction {
type: "ADD_TODO";
payload: { name: string };
}
interface ModifyTodoAction {
type: "TOGGLE_TODO" | "DELETE_TODO";
payload: { id: string };
}
export type TodoAction = AddTodoAction | ModifyTodoAction;
const todoReducer = (todos: Array<TodosProps>, action: TodoAction) => {
switch (action.type) {
case "ADD_TODO":
return [...todos, newTodo(action.payload.name)];
case "TOGGLE_TODO":
return todos.map((todo) => {
if (todo.id === action.payload.id) {
return { ...todo, isComplete: !todo.isComplete };
}
return todo;
});
case "DELETE_TODO":
return todos.filter((todo) => todo.id !== action.payload.id);
default:
return todos;
}
};
const newTodo = (todoName: string): TodosProps => {
return { id: uuidv4(), todoName: todoName, isComplete: false };
};
const Todos: React.FC = () => {
const [todos, dispatch] = useReducer(todoReducer, []);
const renderTodos = todos.map((todo) => (
<Todo
key={todo.id}
id={todo.id}
todoName={todo.todoName}
isComplete={todo.isComplete}
dispatch={dispatch}
/>
));
console.log(todos);
return (
<div>
<TodoInput dispatch={dispatch} />
{renderTodos}
</div>
);
};
export default Todos;
- Create a file called TodoInput.tsx in components folder
TodoInput.tsx
This component is responsible for rendering a form with an input field and a submit button
import * as React from "react";
import { useState } from "react";
import { TodoAction } from "../container/Todos";
interface TodoInputProps {
dispatch: React.Dispatch<TodoAction>;
}
const TodoInput: React.FC<TodoInputProps> = ({ dispatch }) => {
const [todoName, setTodoName] = useState("");
const handleChange = (evt: React.FormEvent<HTMLInputElement>) => {
setTodoName(evt.currentTarget.value);
};
const handleSubmit = (evt: React.FormEvent) => {
evt.preventDefault();
dispatch({ type: "ADD_TODO", payload: { name: todoName } });
setTodoName("");
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Type your todo...."
value={todoName}
onChange={handleChange}
/>
<button type="submit">Add Todo</button>
</form>
);
};
export default TodoInput;
- Display all todo item in Todo.tsx file in components folder
import * as React from "react";
import { TodosProps, TodoAction } from "../container/Todos";
export interface Props extends TodosProps {
dispatch: React.Dispatch<TodoAction>;
}
const Todo: React.FC<Props> = ({ dispatch, id, isComplete, todoName }) => {
const handleDelete = (id: string) => {
dispatch({
type: "DELETE_TODO",
payload: { id: id },
});
};
const handleToggle = (id: string) => {
dispatch({
type: "TOGGLE_TODO",
payload: { id: id },
});
};
return (
<div>
<div>
<p style={{ textDecoration: `${isComplete ? "line-through" : ""}` }}>
{todoName}
</p>
</div>
<div>
<button onClick={() => handleToggle(id)}>Toggle</button>
<button onClick={() => handleDelete(id)}>Delete</button>
</div>
</div>
);
};
export default Todo;
Top comments (0)