React 菜鸟开发教程

从零开始构建现代化 React 应用,涵盖环境搭建、核心概念、实战项目、性能优化全流程,适合完全新手快速入门。

一、前置准备:基础技能与工具

1. 必备基础

  • HTML/CSS :掌握标签语义化、Flex/Grid布局、响应式设计(如@media查询)。

  • JavaScript :重点学习ES6+特性(箭头函数、解构赋值、let/const、模块化import/export)、异步编程(Promiseasync/await)、数组方法(mapfilterreduce)。

  • TypeScript (推荐):静态类型检查,提升代码质量(如接口interface、类型推断)。

2. 开发工具

  • 包管理器 :使用pnpm(更快、更节省空间),替代npm/yarn

  • 代码编辑器 :VS Code(推荐插件:ESLintPrettierReact Developer Tools)。

  • 版本控制 :Git(掌握cloneaddcommitpushpull等基础命令)。

二、环境搭建:Vite + React + TypeScript

2025年主流脚手架,冷启动快、配置简单,适合新手。

1. 创建项目

复制代码
# 使用pnpm(需先安装pnpm:npm install -g pnpm)
pnpm create vite@latest my-react-app -- --template react-ts
cd my-react-app
pnpm install

2. 启动项目

复制代码
pnpm dev

打开http://localhost:5173,看到默认页面即搭建成功。

3. 项目结构说明

复制代码
my-react-app/
├─ src/
│  ├─ app/               # 应用级入口(路由、状态管理)
│  ├─ components/        # 通用组件(如按钮、输入框)
│  ├─ features/          # 业务特性模块(如用户管理、商品列表)
│  ├─ pages/             # 页面组件(如首页、详情页)
│  ├─ hooks/             # 自定义Hooks(如数据请求、表单处理)
│  ├─ assets/            # 静态资源(图片、字体)
│  ├─ styles/            # 全局样式(如Tailwind配置)
│  ├─ lib/               # 工具库(如API请求封装)
│  ├─ test/              # 测试文件(如Jest)
│  ├─ main.tsx           # 入口文件
│  └─ vite-env.d.ts      # TypeScript类型声明
├─ .editorconfig         # 编辑器配置(如缩进、换行)
├─ .eslintrc.cjs         # ESLint代码规范(如禁止未使用变量)
├─ .prettierrc           # Prettier代码格式化(如单引号、分号)
├─ index.html            # 主页面
└─ package.json          # 项目依赖与脚本

三、核心概念:React 基础

1. 组件(Component)

React 应用的核心,将 UI 拆分为可复用的模块(如按钮、表单)。

  • 函数组件(推荐):用函数定义,返回 JSX(JavaScript + HTML)。

    复制代码
    // src/components/Button.tsx
    import React from 'react';
    
    // 定义Props接口(类型约束)
    interface ButtonProps {
      children: React.ReactNode; // 子元素(必选)
      onClick: () => void;       // 点击事件(必选)
      variant?: 'primary' | 'secondary'; // 可选属性(按钮样式)
    }
    
    // 使用React.FC泛型定义组件
    const Button: React.FC<ButtonProps> = ({ children, onClick, variant = 'primary' }) => {
      return (
        <button
          className={`btn-${variant}`} // 动态类名(如btn-primary)
          onClick={onClick}
        >
          {children} // 子元素(如"提交")
        </button>
      );
    };
    
    export default Button;

2. JSX 语法

JavaScript 的扩展语法,用于描述 UI 结构(类似 HTML,但有区别)。

  • 规则

    • className替代 HTML 的class(避免与 JavaScript 关键字冲突)。

    • 单标签必须闭合(如<img /><input />)。

    • 表达式用{}嵌入(如{count}{new Date().toLocaleString()})。

  • 示例

    复制代码
    // src/App.tsx
    import React, { useState } from 'react';
    import Button from './components/Button';
    
    const App: React.FC = () => {
      const [count, setCount] = useState<number>(0); // 状态管理(useState Hook)
    
      // 事件处理函数(驼峰式命名)
      const handleClick = () => {
        setCount(count + 1); // 更新状态(触发重新渲染)
      };
    
      return (
        <div className="app">
          <h1>Hello, React!</h1>
          <p>当前计数:{count}</p>
          <Button onClick={handleClick}>点击增加</Button> {/* 使用自定义组件 */}
        </div>
      );
    };
    
    export default App;

3. 状态管理(State)

组件内部的数据,变化时触发重新渲染。

  • useState Hook(推荐):管理组件状态(如计数、输入框内容)。

    复制代码
    const [count, setCount] = useState<number>(0); // 初始化状态(类型为number)
  • useReducer Hook(复杂状态):用于多状态关联场景(如购物车、表单)。

    复制代码
    // src/hooks/useCart.ts
    import { useReducer, Reducer } from 'react';
    
    // 购物车状态类型
    interface CartItem {
      id: number;
      name: string;
      price: number;
      quantity: number;
    }
    
    interface CartState {
      items: CartItem[];
    }
    
    // 动作类型
    type CartAction =
      | { type: 'add'; item: Omit<CartItem, 'quantity'> }
      | { type: 'remove'; id: number }
      | { type: 'updateQuantity'; id: number; quantity: number };
    
    // Reducer函数(处理状态变化)
    const cartReducer: Reducer<CartState, CartAction> = (state, action) => {
      switch (action.type) {
        case 'add':
          // 检查是否已存在该商品
          const existingItem = state.items.find(item => item.id === action.item.id);
          if (existingItem) {
            return {
              items: state.items.map(item =>
                item.id === action.item.id
                  ? { ...item, quantity: item.quantity + 1 }
                  : item
              )
            };
          } else {
            return {
              items: [...state.items, { ...action.item, quantity: 1 }]
            };
          }
        case 'remove':
          return {
            items: state.items.filter(item => item.id !== action.id)
          };
        case 'updateQuantity':
          return {
            items: state.items.map(item =>
              item.id === action.id
                ? { ...item, quantity: action.quantity }
                : item
            )
          };
        default:
          return state;
      }
    };
    
    // 自定义Hook(封装购物车逻辑)
    const useCart = () => {
      const [state, dispatch] = useReducer(cartReducer, { items: [] });
    
      // 添加商品
      const addItem = (item: Omit<CartItem, 'quantity'>) => {
        dispatch({ type: 'add', item });
      };
    
      // 移除商品
      const removeItem = (id: number) => {
        dispatch({ type: 'remove', id });
      };
    
      // 更新商品数量
      const updateQuantity = (id: number, quantity: number) => {
        dispatch({ type: 'updateQuantity', id, quantity });
      };
    
      return {
        cart: state,
        addItem,
        removeItem,
        updateQuantity
      };
    };
    
    export default useCart;

4. 事件处理

React 中的事件采用驼峰式命名 (如onClickonChange),事件处理函数需绑定this(函数组件无需考虑)。

  • 示例

    复制代码
    // 输入框变化事件
    const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      console.log(e.target.value); // 获取输入框值
    };
    
    // 按钮点击事件
    const handleClick = () => {
      console.log('按钮被点击');
    };
    
    // 在JSX中使用
    <input type="text" onChange={handleInputChange} />
    <button onClick={handleClick}>点击</button>

5. 条件渲染与列表渲染

  • 条件渲染 :用if/else、三元表达式(condition ? true : false)、逻辑与(&&)控制 UI 显示。

    复制代码
    // 三元表达式
    {isLoggedIn ? <div>欢迎回来!</div> : <div>请登录</div>}
    
    // 逻辑与(仅当条件为真时渲染)
    {count > 0 && <div>计数大于0</div>}
  • 列表渲染 :用map遍历数组生成组件,必须添加key属性(唯一标识,提升性能)。

    复制代码
    // 商品列表
    const products = [
      { id: 1, name: '商品1', price: 100 },
      { id: 2, name: '商品2', price: 200 },
      { id: 3, name: '商品3', price: 300 }
    ];
    
    // 渲染列表
    <ul>
      {products.map(product => (
        <li key={product.id}>
          {product.name} - ¥{product.price}
        </li>
      ))}
    </ul>

四、实战项目:Todo List(待办事项)

通过 Todo List 项目,巩固组件、状态管理、事件处理等核心概念。

1. 项目需求

  • 添加待办事项(输入框 + 按钮)。

  • 显示待办事项列表(可标记完成/未完成)。

  • 删除待办事项。

  • 统计未完成数量。

2. 项目结构

复制代码
src/
├─ components/
│  ├─ TodoInput.tsx    # 输入框组件
│  ├─ TodoList.tsx     # 列表组件
│  └─ TodoItem.tsx     # 列表项组件
├─ hooks/
│  └── useTodo.ts      # Todo 状态管理 Hook
├─ App.tsx             # 主组件
└─ main.tsx            # 入口文件

3. 代码实现

(1)自定义 Hook:useTodo(管理 Todo 状态)
复制代码
// src/hooks/useTodo.ts
import { useState, useCallback } from 'react';

// Todo 项类型
interface TodoItem {
  id: number;
  text: string;
  completed: boolean;
}

// useTodo Hook
const useTodo = () => {
  const [todos, setTodos] = useState<TodoItem[]>([]); // Todo 列表
  const [inputValue, setInputValue] = useState<string>(''); // 输入框值

  // 添加 Todo
  const addTodo = useCallback(() => {
    if (inputValue.trim()) {
      const newTodo: TodoItem = {
        id: Date.now(), // 用时间戳作为唯一 ID
        text: inputValue.trim(),
        completed: false
      };
      setTodos(prev => [...prev, newTodo]); // 添加到列表
      setInputValue(''); // 清空输入框
    }
  }, [inputValue]);

  // 切换 Todo 完成状态
  const toggleTodo = useCallback((id: number) => {
    setTodos(prev =>
      prev.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  }, []);

  // 删除 Todo
  const deleteTodo = useCallback((id: number) => {
    setTodos(prev => prev.filter(todo => todo.id !== id));
  }, []);

  // 统计未完成数量
  const uncompletedCount = todos.filter(todo => !todo.completed).length;

  return {
    todos,
    inputValue,
    setInputValue,
    addTodo,
    toggleTodo,
    deleteTodo,
    uncompletedCount
  };
};

export default useTodo;
(2)输入框组件:TodoInput
复制代码
// src/components/TodoInput.tsx
import React from 'react';

// Props 类型
interface TodoInputProps {
  inputValue: string;
  setInputValue: React.Dispatch<React.SetStateAction<string>>;
  addTodo: () => void;
}

const TodoInput: React.FC<TodoInputProps> = ({ inputValue, setInputValue, addTodo }) => {
  // 处理键盘事件(回车添加)
  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter') {
      addTodo();
    }
  };

  return (
    <div className="todo-input">
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        onKeyDown={handleKeyDown}
        placeholder="请输入待办事项"
      />
      <button onClick={addTodo}>添加</button>
    </div>
  );
};

export default TodoInput;
(3)列表项组件:TodoItem
复制代码
// src/components/TodoItem.tsx
import React from 'react';

// Props 类型
interface TodoItemProps {
  todo: {
    id: number;
    text: string;
    completed: boolean;
  };
  toggleTodo: (id: number) => void;
  deleteTodo: (id: number) => void;
}

const TodoItem: React.FC<TodoItemProps> = ({ todo, toggleTodo, deleteTodo }) => {
  return (
    <li className="todo-item">
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => toggleTodo(todo.id)}
      />
      <span
        className={todo.completed ? 'completed' : ''}
        style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
      >
        {todo.text}
      </span>
      <button onClick={() => deleteTodo(todo.id)}>删除</button>
    </li>
  );
};

export default TodoItem;
(4)列表组件:TodoList
复制代码
// src/components/TodoList.tsx
import React from 'react';
import TodoItem from './TodoItem';

// Props 类型
interface TodoListProps {
  todos: {
    id: number;
    text: string;
    completed: boolean;
  }[];
  toggleTodo: (id: number) => void;
  deleteTodo: (id: number) => void;
  uncompletedCount: number;
}

const TodoList: React.FC<TodoListProps> = ({ todos, toggleTodo, deleteTodo, uncompletedCount }) => {
  return (
    <div className="todo-list">
      <h2>待办事项({uncompletedCount} 项未完成)</h2>
      <ul>
        {todos.map(todo => (
          <TodoItem
            key={todo.id}
            todo={todo}
            toggleTodo={toggleTodo}
            deleteTodo={deleteTodo}
          />
        ))}
      </ul>
    </div>
  );
};

export default TodoList;
(5)主组件:App
复制代码
// src/App.tsx
import React from 'react';
import useTodo from './hooks/useTodo';
import TodoInput from './components/TodoInput';
import TodoList from './components/TodoList';
import './App.css'; // 样式文件

const App: React.FC = () => {
  const {
    inputValue,
    setInputValue,
    addTodo,
    todos,
    toggleTodo,
    deleteTodo,
    uncompletedCount
  } = useTodo();

  return (
    <div className="app">
      <h1>Todo List</h1>
      <TodoInput
        inputValue={inputValue}
        setInputValue={setInputValue}
        addTodo={addTodo}
      />
      <TodoList
        todos={todos}
        toggleTodo={toggleTodo}
        deleteTodo={deleteTodo}
        uncompletedCount={uncompletedCount}
      />
    </div>
  );
};

export default App;
(6)样式文件:App.css
复制代码
/* src/App.css */
.app {
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
  font-family: Arial, sans-serif;
}

.todo-input {
  display: flex;
  margin-bottom: 20px;
}

.todo-input input {
  flex: 1;
  padding: 10px;
  font-size: 16px;
  border: 1px solid #ccc;
  border-radius: 4px 0 0 4px;
}

.todo-input button {
  padding: 10px 20px;
  font-size: 16px;
  background-color: #007bff;
  color: #fff;
  border: none;
  border-radius: 0 4px 4px 0;
  cursor: pointer;
}

.todo-list h2 {
  margin-bottom: 10px;
}

.todo-list ul {
  list-style: none;
  padding: 0;
}

.todo-item {
  display: flex;
  align-items: center;
  padding: 10px;
  border-bottom: 1px solid #eee;
}

.todo-item input[type="checkbox"] {
  margin-right: 10px;
}

.todo-item span {
  flex: 1;
  font-size: 16px;
}

.todo-item button {
  padding: 5px 10px;
  font-size: 14px;
  background-color: #dc3545;
  color: #fff;
  border: none;
  border-radius: 4

[](@replace=0)
相关推荐
孤狼warrior3 小时前
纯AI开发能做到什么地步 他心游 经典博客项目
react·ai编程
Hao_Harrision2 天前
50天50个小项目 (React19 + Tailwindcss V4) ✨ | StickyNavbar(粘性导航栏)
前端·typescript·react·tailwindcss·vite7
前端不太难2 天前
从一次点赞操作,看 RN 列表的渲染扩散路径
网络·react
前端不太难3 天前
从 Navigation State 反推架构腐化
前端·架构·react
前端不太难3 天前
Navigation State 与页面内存泄漏的隐性关系
前端·ui·react
weibkreuz3 天前
React开发者工具的下载及安装@4
前端·javascript·react
大模型教程.5 天前
收藏级教程:ReAct模式详解,让大模型从回答问题到解决问题
前端·人工智能·机器学习·前端框架·大模型·产品经理·react
阿里巴啦6 天前
用React+Three.js 做 3D Web版搭建三维交互场景:模型的可视化摆放与轻量交互
前端·react·three.js·模型可视化·web三维·web三维交互场景
Swift社区7 天前
RN 项目中“页面存在 ≠ 页面可见”会导致哪些隐藏 Bug?
react native·bug·react