# React + Axios + JSON Server 实现 Todo 应用

URL: https://caijiao.org/posts/29
Source: docs/posts/29.md
Description: 使用 React + Axios + JSON Server 实现完整 Todo 应用，包括显示列表、添加任务、删除任务、标记完成。适合新手练手项目。

本教程将带你使用 **React** 构建前端，通过 **[Axios](/axios/)** 请求数据，并使用 **JSON Server** 作为本地假接口，实现一个完整的 Todo 应用。

## 准备环境

* Node.js >= 18
* npm 或 yarn
* 了解 [React](/react/) 基础（组件、state、props）

## 搭建 JSON Server

1. 安装 JSON Server：

```bash
npm install -g json-server
```

2. 创建 `db.json` 文件：

```json
{
  "todos": [
    { "id": 1, "title": "学习 React", "completed": false },
    { "id": 2, "title": "写 Todo 应用", "completed": false }
  ]
}
```

3. 启动 JSON Server：

```bash
json-server --watch db.json --port 3001
```

接口示例：

* `GET /todos` 获取任务列表
* `POST /todos` 添加任务
* `DELETE /todos/:id` 删除任务
* `PATCH /todos/:id` 更新任务状态

## 创建 React 项目

1. 使用 Vite 创建 React 项目：

```bash
npm create vite@latest todo-app --template react
cd todo-app
npm install
```

2. 安装 Axios：

```bash
npm install axios
```

## 实现 Todo 功能

### 显示任务列表

创建 `src/components/TodoList.jsx`：

```jsx
import React, { useEffect, useState } from "react";
import axios from "axios";

const API_URL = "http://localhost:3001/todos";

export default function TodoList() {
  const [todos, setTodos] = useState([]);

  useEffect(() => {
    fetchTodos();
  }, []);

  const fetchTodos = async () => {
    const res = await axios.get(API_URL);
    setTodos(res.data);
  };

  return (
    <div>
      <h2>Todo List</h2>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            {todo.title} {todo.completed ? "✅" : ""}
          </li>
        ))}
      </ul>
    </div>
  );
}
```

### 添加任务

```jsx
const [newTitle, setNewTitle] = useState("");

const addTodo = async () => {
  if (!newTitle) return;
  await axios.post(API_URL, { title: newTitle, completed: false });
  setNewTitle("");
  fetchTodos();
};
```

```jsx
<div>
  <input
    type="text"
    value={newTitle}
    onChange={e => setNewTitle(e.target.value)}
    placeholder="输入新任务"
  />
  <button onClick={addTodo}>添加</button>
</div>
```

### 删除任务

```jsx
const deleteTodo = async (id) => {
  await axios.delete(`${API_URL}/${id}`);
  fetchTodos();
};
```

```jsx
<li key={todo.id}>
  {todo.title} {todo.completed ? "✅" : ""}
  <button onClick={() => deleteTodo(todo.id)}>删除</button>
</li>
```

### 标记完成

```jsx
const toggleCompleted = async (todo) => {
  await axios.patch(`${API_URL}/${todo.id}`, { completed: !todo.completed });
  fetchTodos();
};
```

```jsx
<li key={todo.id}>
  <span
    style={{ textDecoration: todo.completed ? "line-through" : "none", cursor: "pointer" }}
    onClick={() => toggleCompleted(todo)}
  >
    {todo.title}
  </span>
  <button onClick={() => deleteTodo(todo.id)}>删除</button>
</li>
```

## 运行效果

1. 启动 JSON Server：

```bash
json-server --watch db.json --port 3001
```

2. 启动 React 项目：

```bash
npm run dev
```

访问 `http://localhost:5173`，即可看到 Todo 应用：

* 点击任务切换完成状态
* 添加新任务
* 删除任务

## 总结

通过本教程，你学会了：

* 使用 **React** 构建组件
* 使用 **Axios** 请求 API
* 使用 **JSON Server** 搭建假数据接口
* 实现 Todo 应用的增删改查功能
