React 环境搭建 + 完整 Demo 教程

一、环境搭建(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;

🚀 进阶扩展建议

学完基础后,你可以尝试:

  1. 添加路由(React Router)

  2. 集成状态管理(Redux/Zustand)

  3. 添加单元测试(Jest + Testing Library)

  4. 对接后端API(axios/fetch)

  5. 部署到Vercel/Netlify

📦 一键启动脚本

如果你想要快速开始,可以直接复制下面的命令:

复制代码
# 一键创建和运行
npm create vite@latest react-todo-demo -- --template react-ts
cd react-todo-demo
npm install
# 复制上面的代码文件
npm run dev

建议:自己动手敲一遍代码,理解每个组件的作用,然后尝试添加新功能(如筛选、搜索、标签等)。

祝你React学习顺利! 🚀

相关推荐
2501_916007472 小时前
React Native 混淆在真项目中的方式,当 JS 和原生同时暴露
javascript·react native·react.js·ios·小程序·uni-app·iphone
IT_陈寒2 小时前
Python性能翻倍的5个隐藏技巧:让你的代码跑得比同事快50%
前端·人工智能·后端
Можно2 小时前
GET与POST深度解析:区别、适用场景与dataType选型指南
前端·javascript
爱上妖精的尾巴2 小时前
5-41 WPS JS宏 数组迭代基础测试与双数组迭代的使用方法测试
前端·javascript·wps
Tisfy2 小时前
“豆包聊天搜索” —— 直接在Chrome等浏览器地址栏开启对话
前端·chrome·豆包
Data_agent2 小时前
京东商品价格历史信息API使用指南
java·大数据·前端·数据库·python
大学生资源网3 小时前
基于Vue的网上购物管理系统的设计与实现(java+vue+源码+文档)
java·前端·vue.js·spring boot·后端·源码
diudiu_333 小时前
XSS跨站脚本攻击
前端·xss
终极前端开发协会3 小时前
【web前端 - 齐枭飞】乾坤【qiankun】应用,主项目与子项目交互详细代码,里面有详细代码,可直接粘贴过去 直接应用 ,
前端·前端框架·交互