一、环境搭建(3种方式任选)
方式1:使用 Vite(最快,最推荐 ✅)
# 创建项目(选择React + TypeScript)
npm create vite@latest react-demo -- --template react-ts
cd react-demo
npm install
npm run dev
方式2:使用 Create React App(传统,稳定)
npx create-react-app react-demo
cd react-demo
npm start
方式3:在线沙盒(无需安装)
-
CodeSandbox- 在线 React 环境
-
StackBlitz- 浏览器中运行 Vite
🚀二、项目结构说明
react-demo/
├── src/
│ ├── App.tsx # 主组件
│ ├── main.tsx # 入口文件
│ ├── index.css # 全局样式
│ └── vite-env.d.ts # 类型定义
├── public/ # 静态资源
├── package.json # 依赖配置
├── tsconfig.json # TS配置
└── vite.config.ts # Vite配置
💡 三、完整实战 Demo:TODO 待办事项应用
步骤1:安装必要依赖
# 进入项目目录后
npm install
npm install @types/react @types/react-dom
npm install antd # 使用Ant Design组件库(可选)
npm install classnames # 条件类名工具
步骤2:创建组件结构
创建 src/components/目录,并添加以下组件:
2.1 TodoItem.tsx - 单个待办项
// src/components/TodoItem.tsx
import React, { useState } from 'react';
import './TodoItem.css';
interface TodoItemProps {
id: number;
text: string;
completed: boolean;
onToggle: (id: number) => void;
onDelete: (id: number) => void;
onEdit: (id: number, newText: string) => void;
}
const TodoItem: React.FC<TodoItemProps> = ({
id,
text,
completed,
onToggle,
onDelete,
onEdit
}) => {
const [isEditing, setIsEditing] = useState(false);
const [editText, setEditText] = useState(text);
const handleSave = () => {
if (editText.trim()) {
onEdit(id, editText);
setIsEditing(false);
}
};
return (
<div className={`todo-item ${completed ? 'completed' : ''}`}>
<div className="todo-content">
<input
type="checkbox"
checked={completed}
onChange={() => onToggle(id)}
className="todo-checkbox"
/>
{isEditing ? (
<div className="edit-mode">
<input
type="text"
value={editText}
onChange={(e) => setEditText(e.target.value)}
className="edit-input"
autoFocus
/>
<button onClick={handleSave} className="btn save-btn">保存</button>
<button onClick={() => setIsEditing(false)} className="btn cancel-btn">取消</button>
</div>
) : (
<div className="view-mode">
<span className="todo-text" onDoubleClick={() => setIsEditing(true)}>
{text}
</span>
<div className="todo-actions">
<button
onClick={() => setIsEditing(true)}
className="btn edit-btn"
title="编辑"
>
✏️
</button>
<button
onClick={() => onDelete(id)}
className="btn delete-btn"
title="删除"
>
🗑️
</button>
</div>
</div>
)}
</div>
</div>
);
};
export default TodoItem;
2.2 TodoList.tsx - 待办列表
// src/components/TodoList.tsx
import React from 'react';
import TodoItem from './TodoItem';
import './TodoList.css';
interface Todo {
id: number;
text: string;
completed: boolean;
}
interface TodoListProps {
todos: Todo[];
onToggleTodo: (id: number) => void;
onDeleteTodo: (id: number) => void;
onEditTodo: (id: number, newText: string) => void;
}
const TodoList: React.FC<TodoListProps> = ({
todos,
onToggleTodo,
onDeleteTodo,
onEditTodo
}) => {
if (todos.length === 0) {
return (
<div className="empty-state">
<p>🎉 没有待办事项,添加一个吧!</p>
</div>
);
}
return (
<div className="todo-list">
{todos.map(todo => (
<TodoItem
key={todo.id}
id={todo.id}
text={todo.text}
completed={todo.completed}
onToggle={onToggleTodo}
onDelete={onDeleteTodo}
onEdit={onEditTodo}
/>
))}
</div>
);
};
export default TodoList;
2.3 TodoForm.tsx - 添加待办表单
// src/components/TodoForm.tsx
import React, { useState } from 'react';
import './TodoForm.css';
interface TodoFormProps {
onAddTodo: (text: string) => void;
}
const TodoForm: React.FC<TodoFormProps> = ({ onAddTodo }) => {
const [inputValue, setInputValue] = useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (inputValue.trim()) {
onAddTodo(inputValue);
setInputValue('');
}
};
return (
<form className="todo-form" onSubmit={handleSubmit}>
<div className="form-group">
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="请输入待办事项..."
className="todo-input"
/>
<button type="submit" className="add-btn">
添加
</button>
</div>
</form>
);
};
export default TodoForm;
步骤3:主组件 App.tsx
// src/App.tsx
import React, { useState, useEffect } from 'react';
import TodoForm from './components/TodoForm';
import TodoList from './components/TodoList';
import TodoStats from './components/TodoStats';
import './App.css';
interface Todo {
id: number;
text: string;
completed: boolean;
}
function App() {
const [todos, setTodos] = useState<Todo[]>([
{ id: 1, text: '学习 React Hooks', completed: true },
{ id: 2, text: '完成 Todo App 开发', completed: false },
{ id: 3, text: '阅读 TypeScript 文档', completed: false },
]);
// 从 localStorage 加载数据
useEffect(() => {
const savedTodos = localStorage.getItem('todos');
if (savedTodos) {
setTodos(JSON.parse(savedTodos));
}
}, []);
// 保存到 localStorage
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos));
}, [todos]);
// 添加待办
const addTodo = (text: string) => {
const newTodo: Todo = {
id: Date.now(),
text,
completed: false
};
setTodos([...todos, newTodo]);
};
// 切换完成状态
const toggleTodo = (id: number) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
// 删除待办
const deleteTodo = (id: number) => {
setTodos(todos.filter(todo => todo.id !== id));
};
// 编辑待办
const editTodo = (id: number, newText: string) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, text: newText } : todo
));
};
// 清空已完成
const clearCompleted = () => {
setTodos(todos.filter(todo => !todo.completed));
};
return (
<div className="app">
<header className="app-header">
<h1>📝 React Todo App</h1>
<p>一个完整的 React + TypeScript 待办事项应用</p>
</header>
<main className="app-main">
<div className="todo-container">
<div className="card">
<TodoForm onAddTodo={addTodo} />
<TodoStats
todos={todos}
onClearCompleted={clearCompleted}
/>
<TodoList
todos={todos}
onToggleTodo={toggleTodo}
onDeleteTodo={deleteTodo}
onEditTodo={editTodo}
/>
</div>
<div className="features">
<h3>✨ 功能特性</h3>
<ul>
<li>✅ 添加/删除/编辑待办</li>
<li>✅ 标记完成状态</li>
<li>✅ 双击编辑</li>
<li>✅ 数据本地存储</li>
<li>✅ 响应式设计</li>
<li>✅ TypeScript 类型安全</li>
</ul>
</div>
</div>
</main>
<footer className="app-footer">
<p>使用 React + TypeScript + Vite 构建</p>
<p>总任务: {todos.length} | 已完成: {todos.filter(t => t.completed).length} | 未完成: {todos.filter(t => !t.completed).length}</p>
</footer>
</div>
);
}
export default App;
🚀 进阶扩展建议
学完基础后,你可以尝试:
-
添加路由(React Router)
-
集成状态管理(Redux/Zustand)
-
添加单元测试(Jest + Testing Library)
-
对接后端API(axios/fetch)
-
部署到Vercel/Netlify
📦 一键启动脚本
如果你想要快速开始,可以直接复制下面的命令:
# 一键创建和运行
npm create vite@latest react-todo-demo -- --template react-ts
cd react-todo-demo
npm install
# 复制上面的代码文件
npm run dev
建议:自己动手敲一遍代码,理解每个组件的作用,然后尝试添加新功能(如筛选、搜索、标签等)。
祝你React学习顺利! 🚀