返回

TypeScript+React Hooks+Redux构建Todo应用:全栈指南

前端

前言

在现代Web开发中,TypeScript、React和Redux是三个非常流行的工具。TypeScript是一种对JavaScript的超集,它可以帮助我们编写出更健壮、更易维护的代码。React是一个用于构建用户界面的JavaScript库,它以其声明式编程风格和高性能而著称。Redux是一个用于管理应用程序状态的JavaScript库,它以其可预测性、可调试性和可扩展性而备受欢迎。

本文将指导您使用这三个工具来构建一个完整的Todo应用。我们将从项目搭建开始,逐步学习如何使用这些技术来构建一个功能齐全的Todo应用,包括添加、删除、编辑和完成任务等功能。此外,您还将学习如何使用Redux来管理应用程序的状态,以实现更好的可扩展性和可维护性。

项目搭建

首先,我们创建一个新的React项目。您可以使用create-react-app工具来轻松完成此步骤。

npx create-react-app todo-app --template typescript

这将创建一个名为todo-app的项目,并安装必要的依赖项。

接下来,我们需要安装TypeScript和Redux。

npm install --save typescript @types/react @types/react-dom
npm install --save redux react-redux

安装完成后,我们需要在项目中配置TypeScript。在tsconfig.json文件中,将compilerOptions.target设置为ES5,并将module设置为commonjs。

{
  "compilerOptions": {
    "target": "ES5",
    "module": "commonjs"
  }
}

最后,我们需要在项目中配置Redux。在src/index.js文件中,导入Redux并创建一个store。

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

const store = createStore(todoReducer);

export default store;

使用React Hooks构建组件

React Hooks是React 16.8中引入的一组新特性,它允许我们在函数组件中使用状态和生命周期方法。在我们的Todo应用中,我们将使用Hooks来构建组件。

首先,让我们创建一个TodoItem组件。该组件将负责渲染单个待办事项。

import React, { useState } from 'react';

const TodoItem = ({ todo, onDelete, onToggle }) => {
  const [completed, setCompleted] = useState(todo.completed);

  const handleToggle = () => {
    setCompleted(!completed);
    onToggle(todo.id);
  };

  const handleDelete = () => {
    onDelete(todo.id);
  };

  return (
    <li className={completed ? 'completed' : ''}>
      <div className="view">
        <input
          className="toggle"
          type="checkbox"
          checked={completed}
          onChange={handleToggle}
        />
        <label>{todo.title}</label>
        <button className="destroy" onClick={handleDelete} />
      </div>
    </li>
  );
};

export default TodoItem;

接下来,让我们创建一个TodoList组件。该组件将负责渲染所有待办事项。

import React, { useState } from 'react';
import TodoItem from './TodoItem';

const TodoList = ({ todos, onDelete, onToggle }) => {
  return (
    <ul className="todo-list">
      {todos.map((todo) => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onDelete={onDelete}
          onToggle={onToggle}
        />
      ))}
    </ul>
  );
};

export default TodoList;

最后,让我们创建一个TodoApp组件。该组件将负责渲染整个应用。

import React, { useState } from 'react';
import TodoList from './TodoList';

const TodoApp = () => {
  const [todos, setTodos] = useState([
    { id: 1, title: 'Learn TypeScript', completed: false },
    { id: 2, title: 'Learn React Hooks', completed: false },
    { id: 3, title: 'Learn Redux', completed: false }
  ]);

  const handleAddTodo = (title) => {
    const newTodo = { id: Date.now(), title, completed: false };
    setTodos([...todos, newTodo]);
  };

  const handleDeleteTodo = (id) => {
    const filteredTodos = todos.filter((todo) => todo.id !== id);
    setTodos(filteredTodos);
  };

  const handleToggleTodo = (id) => {
    const updatedTodos = todos.map((todo) => {
      if (todo.id === id) {
        todo.completed = !todo.completed;
      }
      return todo;
    });
    setTodos(updatedTodos);
  };

  return (
    <div className="todo-app">
      <h1>Todo List</h1>
      <input
        className="new-todo"
        placeholder="What needs to be done?"
        onKeyPress={(e) => {
          if (e.key === 'Enter') {
            handleAddTodo(e.target.value);
          }
        }}
      />
      <TodoList
        todos={todos}
        onDelete={handleDeleteTodo}
        onToggle={handleToggleTodo}
      />
    </div>
  );
};

export default TodoApp;

使用Redux管理状态

现在,让我们使用Redux来管理应用程序的状态。首先,我们需要创建一个todoReducer。该reducer将负责管理与待办事项相关的所有状态。

import { createSlice } from '@reduxjs/toolkit';

const initialState = {
  todos: [
    { id: 1, title: 'Learn TypeScript', completed: false },
    { id: 2, title: 'Learn React Hooks', completed: false },
    { id: 3, title: 'Learn Redux', completed: false }
  ]
};

export const todoSlice = createSlice({
  name: 'todo',
  initialState,
  reducers: {
    addTodo: (state, action) => {
      state.todos.push(action.payload);
    },
    deleteTodo: (state, action) => {
      state.todos = state.todos.filter((todo) => todo.id !== action.payload);
    },
    toggleTodo: (state, action) => {
      const todo = state.todos.find((todo) => todo.id === action.payload);
      todo.completed = !todo.completed;
    }
  }
});

export const { addTodo, deleteTodo, toggleTodo } = todoSlice.actions;

export default todoSlice.reducer;

接下来,我们需要在store中注册todoReducer。

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

const store = createStore(
  combineReducers({
    todo: todoSlice.reducer
  })
);

export default store;

最后,我们需要在组件中使用Redux。

import { useSelector, useDispatch } from 'react-redux';
import { addTodo, deleteTodo, toggleTodo } from '../reducers/todoReducer';

const TodoApp = () => {
  const todos = useSelector((state) => state.todo.todos);
  const dispatch = useDispatch();

  const handleAddTodo = (title) => {
    dispatch(addTodo(title));
  };

  const handleDeleteTodo = (id) => {
    dispatch(deleteTodo(id));
  };

  const handleToggleTodo = (id) => {
    dispatch(toggleTodo(id));
  };

  return (
    <div className="todo-app">
      <h1>Todo List</h1>
      <input
        className="new-todo"
        placeholder="What needs to be done?"
        onKeyPress={(e) => {
          if (e.key === 'Enter') {
            handleAddTodo(e.target.value);
          }
        }}
      />
      <TodoList
        todos={todos}
        onDelete={handleDeleteTodo}
        onToggle={handleToggleTodo}
      />
    </div>
  );
};

export default TodoApp;

现在,我们的应用已经能够使用Redux来管理状态了。

总结

本文介绍了如何使用TypeScript、React Hooks和Redux来构建一个完整的Todo应用。我们从项目搭建开始,逐步学习如何使用这些技术来构建一个功能齐全的Todo应用,包括添加、删除、编辑和完成任务等功能。此外,