Building a Redux-Managed Todo List in React with React-Redux
Vivek Neupane
IT DEPENDS - FullStack Developer | ReactJS | NextJS | Astro | NodeJS | Express | MongoDB | Firebase | AWS | React Native
Introduction
In web applications, managing state efficiently is essential, especially in complex UIs with dynamic interactions. Redux, a powerful state management library, simplifies this by providing a single source of truth for the application's state. In this tutorial, we'll build a Todo List app in React with Redux, where users can add and delete items from their to-do list.
Setting Up Redux
Redux Toolkit makes integrating Redux into a React project easier by providing utilities like configureStore and createSlice. Here’s how to configure Redux for a to-do list application.
npm install @reduxjs/toolkit react-redux
2. Create the Store: The store holds the state of the application. In store.js, we set up the store to use a slice we’ll define shortly.
import { configureStore } from "@reduxjs/toolkit";
import todoReducer from './utils/todoSlice';
export default configureStore({
reducer: {
todo: todoReducer
}
});
Creating a Redux Slice for Todos
Redux Toolkit’s createSlice function helps you set up a slice of state with action creators and reducers. Here’s how the slice for todos looks:
import { createSlice } from "@reduxjs/toolkit";
export const todoSlice = createSlice({
name: 'todo',
initialState: {
items: []
},
reducers: {
addTodo: (state, action) => {
state.items.push(action.payload);
},
removeTodo: (state, action) => {
state.items = state.items.filter(item => item !== action.payload);
}
}
});
export const { addTodo, removeTodo } = todoSlice.actions;
export default todoSlice.reducer;
Building the Todo Component
Now, we’ll build a Todo component to add and remove todos. This component uses useSelector to access the current list of todos and useDispatch to dispatch actions for adding and removing items.
Here’s the code:
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { addTodo, removeTodo } from "../utils/todoSlice";
export default function Todo() {
const todos = useSelector((state) => state.todo.items);
const dispatch = useDispatch();
const [inputValue, setInputValue] = useState("");
const handleAddTodo = () => {
if (inputValue.trim()) {
dispatch(addTodo(inputValue));
setInputValue("");
}
};
return (
<div>
<h1>Todo List</h1>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Enter a new todo"
/>
<button onClick={handleAddTodo}>Add Todo</button>
<h2>Your Todos:</h2>
<ul>
{todos.map((todo, index) => (
<li key={index}>
{todo}
<button onClick={() => dispatch(removeTodo(todo))}>
Delete
</button>
</li>
))}
</ul>
</div>
);
}
Final Steps
Make sure to wrap your app with Provider in the root component to provide access to the Redux store:
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import store from "./store";
import Todo from "./components/Todo";
ReactDOM.render(
<Provider store={store}>
<Todo />
</Provider>,
document.getElementById("root")
);
Conclusion
With Redux, managing application state becomes much more predictable and centralized. In this to-do list application, we saw how to create a slice to handle addTodo and removeTodo actions, define a Redux store, and use React Redux hooks (useDispatch and useSelector) in our component. This setup is highly extensible, allowing us to add more features and actions easily. By mastering Redux Toolkit’s straightforward API, you’re well on your way to building scalable React applications.