Redux Toolkit (Todo)

  • Main.jsx:

    • The Provider component from react-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 the store to the Provider.

    • 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 and Todo for displaying tasks.

    • The Provider ensures the store 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 from react-redux, and the Redux store.

    • Wraps the App component with the Provider 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 the Todo 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 by nanoid) and text (from the action payload).

    • removeTodo:

      • Removes a todo from the todos array.

      • Filters out the todo whose id matches the action.payload.

  • Exports:

    • addTodo and removeTodo 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 the addTodo action.

  • Key Features:

    1. State Management:

      • Uses useState to manage the input value for the todo.
    2. Dispatching Actions:

      • The useDispatch hook provides the dispatch function, used to call the addTodo reducer and update the Redux store.
    3. Event Handling:

      • On form submission, the addTodoHandler dispatches the addTodo action with the input value.

Todo.jsx

  • Purpose:

    • Displays the list of todos.

    • Allows users to delete todos using the removeTodo action.

  • Key Features:

    1. Accessing State:

      • Uses useSelector to access the todos array from the Redux store.
    2. Dispatching Actions:

      • The useDispatch hook is used to call the removeTodo action to delete a todo by its ID.
    3. Dynamic Rendering:

      • Maps over the todos array to display each todo in a list item.

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;