Redux Toolkit (Todo)
Main.jsx:
The
Provider
component fromreact-redux
is used to wrap the entire application to give all components access to the Redux store.Instead of passing a
value
prop (as used in React Context), we pass thestore
to theProvider
.createRoot
is used to initialize the React application and render the root component (App
).
App.jsx:
The
App
component acts as the main container for the application.It includes two child components:
AddTodo
for adding tasks andTodo
for displaying tasks.The
Provider
ensures thestore
is accessible to these components, enabling them to interact with the Redux store.
Code Explanation
Main.jsx:
Imports necessary modules including
StrictMode
, React DOM methods,Provider
fromreact-redux
, and the Reduxstore
.Wraps the
App
component with theProvider
component to connect the Redux store to the React app.
App.jsx:
Imports styles and renders the main UI structure.
The
AddTodo
component handles adding new tasks, while theTodo
component displays and manages the list of tasks.React fragments (
<>...</>
) are used to group multiple elements without adding an extra node to the DOM.
Complete Code
Main.jsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.jsx';
import { Provider } from 'react-redux';
import { store } from './app/store.js';
createRoot(document.getElementById('root')).render(
<Provider store={store}>
<App />
</Provider>
);
App.jsx
import './App.css';
import AddTodo from './components/AddTodo';
import Todo from './components/Todo';
function App() {
return (
<>
<h1>Learn about redux toolkit</h1>
<AddTodo />
<Todo />
</>
);
}
export default App;
Purpose of
todoSlice.js
:This file defines the Redux slice for managing todos using the Redux Toolkit.
A slice is a part of the Redux store with its state and reducers grouped together.
Key Concepts:
createSlice
is used to create a slice of the Redux store. It includes:The slice name (
name
).The initial state (
initialState
).Reducers that define how state updates are handled.
The
nanoid
function generates unique IDs for todos.Actions (
addTodo
,removeTodo
) modify the state using the payload provided.
Reducers:
addTodo
:Adds a new todo to the
todos
array.Each todo is an object with an
id
(generated bynanoid
) andtext
(from the action payload).
removeTodo
:Removes a todo from the
todos
array.Filters out the todo whose
id
matches theaction.payload
.
Exports:
addTodo
andremoveTodo
are exported as actions for use in components.The slice reducer is exported as the default export.
Code Explanation
Key Features of the Code:
Initial State:
- Defines the structure of the state, starting with one sample todo.
Reducers:
The
addTodo
reducer adds new todos dynamically.The
removeTodo
reducer removes todos based on their ID.
Exports:
Actions are named exports to dispatch specific changes to the state.
Reducer is the default export to register in the Redux store.
Complete Code
todoSlice.js
import { createSlice, nanoid } from "@reduxjs/toolkit";
// Initial state defines the structure of the todos
const initialState = {
todos: [
{
id: 1,
text: "helllo",
},
],
};
// Create a slice for managing todos
export const todoSlice = createSlice({
name: "todo",
initialState,
reducers: {
// Action to add a new todo
addTodo: (state, action) => {
const todo = {
id: nanoid(), // Generate a unique ID
text: action.payload, // The todo text from the action payload
};
state.todos.push(todo); // Add the new todo to the state
},
// Action to remove a todo by ID
removeTodo: (state, action) => {
state.todos = state.todos.filter((todo) => todo.id !== action.payload);
},
},
});
// Export actions for adding and removing todos
export const { addTodo, removeTodo } = todoSlice.actions;
// Export the reducer as the default export
export default todoSlice.reducer;
AddTodo.jsx
Purpose:
Provides a form for users to add new todos.
Uses
useDispatch
from React-Redux to dispatch theaddTodo
action.
Key Features:
State Management:
- Uses
useState
to manage the input value for the todo.
- Uses
Dispatching Actions:
- The
useDispatch
hook provides thedispatch
function, used to call theaddTodo
reducer and update the Redux store.
- The
Event Handling:
- On form submission, the
addTodoHandler
dispatches theaddTodo
action with the input value.
- On form submission, the
Todo.jsx
Purpose:
Displays the list of todos.
Allows users to delete todos using the
removeTodo
action.
Key Features:
Accessing State:
- Uses
useSelector
to access thetodos
array from the Redux store.
- Uses
Dispatching Actions:
- The
useDispatch
hook is used to call theremoveTodo
action to delete a todo by its ID.
- The
Dynamic Rendering:
- Maps over the
todos
array to display each todo in a list item.
- Maps over the
Complete Code
AddTodo.jsx
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { addTodo } from "../features/todo/todoSlice";
const AddTodo = () => {
// State to handle the input value
const [input, setInput] = useState("");
// Dispatch function from React-Redux
const dispatch = useDispatch();
// Handler to add a new todo
const addTodoHandler = (e) => {
e.preventDefault();
if (input.trim()) {
dispatch(addTodo(input)); // Dispatch the addTodo action
setInput(""); // Clear the input field
}
};
return (
<form onSubmit={addTodoHandler} className="space-x-3 mt-12">
<input
type="text"
className="bg-gray-800 rounded border border-gray-700 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-900 text-base outline-none text-gray-100 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
placeholder="Enter a Todo..."
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<button
type="submit"
className="text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg"
>
Add Todo
</button>
</form>
);
};
export default AddTodo;
Todo.jsx
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { removeTodo } from "../features/todo/todoSlice";
const Todo = () => {
// Access todos from the Redux store
const todos = useSelector((state) => state.todos);
// Dispatch function from React-Redux
const dispatch = useDispatch();
return (
<>
<div className="text-lg font-bold mb-4 text-white">Todos</div>
<ul className="list-none">
{todos.map((todo) => (
<li
key={todo.id}
className="mt-4 flex justify-between items-center bg-zinc-800 px-4 py-2 rounded"
>
<div className="text-white">{todo.text}</div>
<button
onClick={() => dispatch(removeTodo(todo.id))}
className="text-white bg-red-500 border-0 py-1 px-4 focus:outline-none hover:bg-red-600 rounded text-md flex items-center"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-6 h-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</button>
</li>
))}
</ul>
</>
);
};
export default Todo;