Using React and Redux to Build a Todo List Application

This guide walks through creating a React Todo List app with Redux by installing the libraries, defining TypeScript state and actions for adding and deleting items, implementing an immutable reducer, configuring a store, wrapping the root with Provider, and connecting UI components to dispatch and display the todo array, illustrating the full Redux workflow and its debugging advantages.

Ximalaya Technology Team
Ximalaya Technology Team
Ximalaya Technology Team
Using React and Redux to Build a Todo List Application

Some students reported that state management in React Native is not very clear. This article introduces the typical workflow of using Redux for state management in both React and React Native, comparing its usage and pros/cons.

First, we demonstrate how to set up a React project and install Redux-related libraries.

npx create-react-app playpage_ts --template typescript
npm install @reduxjs/toolkit react-redux

Next, we define the data structures. In this example, a TODO is simply a text string, and the overall state contains an array of todos.

export type TODO = {
    text: string
}

export type State = {
    todos: TODO[]
}

We then define action types and action creators for adding and deleting todos.

// action types
export const ADD_TODO = 'ADD_TODO';
export const DELETE_TODO = 'DELETE_TODO';

// action creators
const ACTION_CREATOR_ADD_TODO = (text: string) => ({ type: ADD_TODO, payload: text });
const ACTION_CREATOR_DELETE_TODO = (text: string) => ({ type: DELETE_TODO, payload: text });

export function DISPATCH_ADD_TODO(dispatch: any) {
    return (text: string) => { dispatch(ACTION_CREATOR_ADD_TODO(text)); };
}

export function DISPATCH_DELETE_TODO(dispatch: any) {
    return (text: string) => { dispatch(ACTION_CREATOR_DELETE_TODO(text)); };
}

The reducer processes these actions and returns a new state without mutating the previous one.

import { State, TODO } from "./model";
import { ADD_TODO, DELETE_TODO } from "./todoActions";

const initState: State = {
    todos: [{ text: "clean room" }]
};

const todoReducer = (state: State = initState, action: any): State => {
    switch (action.type) {
        case ADD_TODO:
            return { todos: [...state.todos, { text: action.payload }] };
        case DELETE_TODO:
            const todos = state.todos.filter(item => item.text !== action.payload);
            return { todos };
        default:
            return state;
    }
};

export default todoReducer;

We create a Redux store using the reducer.

import { createStore } from 'redux';
import todoReducer from './reducers';

const store = createStore(todoReducer);
store.subscribe(() => {
    console.log('store changed >>>' + JSON.stringify(store.getState()));
});
export default store;

To make the store available to the whole React app, we wrap the root component with Provider from react-redux.

import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import ReduxTodoApp from './ReduxTodoApp';
import store from './redux/store';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
    <Provider store={store}>
        <ReduxTodoApp/>
    </Provider>
);

The UI component ( ReduxTodoApp) receives the todo list and dispatch functions via props.

import { useState } from "react";
import { connect } from "react-redux";
import { State, TODO } from "./redux/model";
import { DISPATCH_ADD_TODO, DISPATCH_DELETE_TODO } from "./redux/todoActions";

function ReduxTodoApp({ todos, addTodo, deleteTodo }: { todos: TODO[]; addTodo: any; deleteTodo: any }) {
    const [text, setText] = useState('');
    const handleAddTodo = () => { addTodo(text); setText(''); };
    const handleDeleteTodo = (t: string) => { deleteTodo(t); };
    return (
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
            <h1>This Is Redux TODO App.</h1>
            <ul>
                {todos.map((todo, index) => (
                    <li key={index}>
                        <span>{todo.text}</span>
                        <button style={{ marginLeft: '12px' }} onClick={() => handleDeleteTodo(todo.text)}>finish</button>
                    </li>
                ))}
            </ul>
            <div style={{ display: 'flex', flexDirection: 'row' }}>
                <input value={text} onChange={e => setText(e.target.value)} />
                <button onClick={handleAddTodo}>Add Todo</button>
            </div>
        </div>
    );
}

const mapStateToProps = (state: State) => ({ todos: state.todos });
const mapDispatchToProps = (dispatch: any) => ({
    addTodo: DISPATCH_ADD_TODO(dispatch),
    deleteTodo: DISPATCH_DELETE_TODO(dispatch)
});

export default connect(mapStateToProps, mapDispatchToProps)(ReduxTodoApp);

In summary, the classic Redux workflow consists of:

Define the data structure (State).

Define action types and creators (e.g., ADD_TODO, DELETE_TODO).

Implement a reducer that returns a new state based on the action.

Create a global store with createStore.

Wrap the app with Provider to expose the store.

Use connect (or hooks) in UI components to map state to props and dispatch actions.

This separation of actions and reducers makes the codebase easier to extend and debug, providing the traceability that Redux promises.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TypeScriptReduxState ManagementReactfront-end developmentTodo App
Ximalaya Technology Team
Written by

Ximalaya Technology Team

Official account of Ximalaya's technology team, sharing distilled technical experience and insights to grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.