手册说明

本手册是一份结构化、可查阅、从入门到进阶的 React 综合指南,适用于前端初学者快速入门 React,也可作为中高级开发者的日常参考工具书。手册涵盖 React 核心语法、常用 API、工程化实践、路由与状态管理、性能优化等核心内容,所有示例代码均可直接复用。

目录

  1. 基础准备:环境搭建与项目结构
  2. 核心语法:JSX 与组件基础
  3. 数据管理:Props 与 State 核心
  4. 钩子函数:Hooks 全解析(核心 + 自定义)
  5. 组件通信:父子 / 跨组件 / 兄弟通信方案
  6. 路由管理:React Router v6 实战
  7. 状态管理:从内置方案到主流库
  8. 样式方案:多种 React 样式实现
  9. 性能优化:组件与项目级优化技巧
  10. 工程化:规范、打包与部署
  11. 实战案例:整合核心知识点
  12. 附录:API 速查 & 常见问题

1. 基础准备:环境搭建与项目结构

1.1 前置依赖

React 基于 JavaScript 开发,需提前安装:

1.2 项目搭建(两种主流方案)

方案 1:Vite + React(推荐,高性能)

Vite 是新一代前端构建工具,启动速度、热更新效率远超传统 CRA。
bash
 
运行
 
 
 
 
# 1. 创建项目
npm create vite@latest my-react-vite-app -- --template react  # React + JavaScript
# 若使用 TypeScript:--template react-ts

# 2. 进入项目目录
cd my-react-vite-app

# 3. 安装依赖
npm install

# 4. 启动开发服务(默认端口 5173)
npm run dev

# 5. 生产环境打包(输出到 dist 目录)
npm run build

# 6. 预览打包后的项目
npm run preview
 

方案 2:Create React App(CRA,传统稳定)

bash
 
运行
 
 
 
 
# 1. 创建项目
npx create-react-app my-react-cra-app  # JavaScript 版本
# TypeScript 版本:npx create-react-app my-react-cra-app --template typescript

# 2. 进入目录
cd my-react-cra-app

# 3. 启动开发服务(默认端口 3000)
npm start

# 4. 生产环境打包(输出到 build 目录)
npm run build

# 5. 测试(可选)
npm test
 

1.3 项目结构解析(Vite + React)

plaintext
 
 
 
 
 
my-react-vite-app/
├── node_modules/        # 项目依赖包
├── dist/                # 生产环境打包输出目录
├── public/              # 静态资源(不会被 Vite 编译,直接复制到 dist)
│   └── favicon.ico      # 网站图标
├── src/                 # 核心源码目录(开发重点)
│   ├── assets/          # 静态资源(会被 Vite 编译,如图片、CSS)
│   ├── components/      # 公共组件(可复用,如 Button、Card)
│   ├── pages/           # 页面组件(路由对应页面,如 Home、About)
│   ├── App.jsx          # 根组件
│   ├── main.jsx         # 入口文件(挂载 React 到 DOM)
│   └── index.css        # 全局样式
├── .gitignore           # Git 忽略配置
├── index.html           # 入口 HTML(Vite 特有,挂载根节点)
├── package.json         # 项目配置(依赖、脚本命令)
└── vite.config.js       # Vite 配置文件
 

1.4 入口文件解析(main.jsx)

React 18 新增 createRoot API,替代传统 ReactDOM.render,支持并发渲染特性。
jsx
 
 
 
 
 
// src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'

// 1. 获取 DOM 根节点(对应 index.html 中的 <div id="root"></div>)
const root = ReactDOM.createRoot(document.getElementById('root'))

// 2. 挂载 React 根组件
root.render(
  // StrictMode:严格模式,检查组件潜在问题(仅开发环境生效)
  <React.StrictMode>
    <App />
  </React.StrictMode>
)
 

2. 核心语法:JSX 与组件基础

2.1 JSX 语法详解

JSX(JavaScript XML)是 React 的语法糖,允许在 JavaScript 中书写类 HTML 结构,最终会被 @babel/plugin-transform-react-jsx 编译为 React.createElement() 调用。

2.1.1 JSX 核心规则

规则 说明 示例
标签必须闭合 单标签加 /,双标签必须成对 正确:<img src="" alt="" />、<div></div>
 
错误:<img src="" alt="">
根节点限制 React 18 支持多根节点,低版本需包裹 多根节点:<h1>标题</h1><p>内容</p>
 
包裹方式:<div>...</div>、<>(空片段)、<Fragment>...</Fragment>
嵌入 JS 表达式 用 {} 包裹,支持变量、函数调用等 {name}、{1 + 2}、{isShow ? '显示' : '隐藏'}、{formatDate(time)}
属性驼峰命名 替代 HTML 中的短横线命名 className(替代 class)、onClick(替代 onclick)、tabIndex(替代 tab-index)
样式绑定 行内样式需传入对象,属性驼峰命名 style={{ color: 'red', fontSize: '16px', margin: '10px 0' }}
注释写法 必须包裹在 {} 中 {/* 这是 JSX 注释 */}
避免 if/for 直接使用 可在外层使用,或用三元表达式、map 替代 列表渲染:todos.map(todo => <li key={todo.id}>{todo.text}</li>)

2.1.2 JSX 编译示例

jsx
 
 
 
 
 
// 编写的 JSX 代码
const element = (
  <div className="greeting" onClick={() => console.log('hello')}>
    <h1>Hello, {name}!</h1>
  </div>
);

// 编译后的 JavaScript 代码(React 内部执行)
const element = React.createElement(
  'div',
  { className: 'greeting', onClick: () => console.log('hello') },
  React.createElement('h1', null, `Hello, ${name}!`)
);
 

2.2 组件基础

组件是 React 应用的最小构建单元,用于封装 UI 结构、样式和行为,支持复用。React 组件分为 函数组件(现代主流)和 类组件(传统方案,逐步淘汰)。

2.2.1 函数组件(推荐)

jsx
 
 
 
 
 
// 方式1:箭头函数(推荐,简洁易读)
const Button = (props) => {
  // 解构 props,简化使用
  const { text, onClick } = props;
  return <button onClick={onClick}>{text}</button>;
};

// 方式2:普通函数
function Input({ placeholder, value, onChange }) {
  return <input placeholder={placeholder} value={value} onChange={onChange} />;
}

// 方式3:无 props 简化写法
const HelloWorld = () => {
  return <h1>Hello React!</h1>;
};
 

2.2.2 类组件(了解即可,逐步淘汰)

jsx
 
 
 
 
 
import React, { Component } from 'react';

class Counter extends Component {
  // 类组件状态(旧版)
  state = {
    count: 0
  };

  // 事件处理(需绑定 this,或用箭头函数)
  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };

  // 必须实现 render 方法
  render() {
    return (
      <div>
        <p>计数:{this.state.count}</p>
        <button onClick={this.increment}>点击加1</button>
      </div>
    );
  }
}
 

2.2.3 组件的导出与导入

组件需导出后才能在其他文件中使用,支持默认导出和命名导出。
导出方式 语法 导入语法 特点
默认导出 export default Button; import Button from './Button'; 一个文件只能有一个默认导出,导入时可自定义名称
命名导出 export const Button = () => {}; import { Button } from './Button'; 一个文件可多个命名导出,导入时名称需与导出一致(可别名)
jsx
 
 
 
 
 
// ./components/Button.jsx
// 默认导出
const Button = ({ text }) => <button>{text}</button>;
export default Button;

// 命名导出
export const PrimaryButton = ({ text }) => (
  <button style={{ backgroundColor: 'blue', color: 'white' }}>{text}</button>
);

// 导入使用(./App.jsx)
import Button from './components/Button';
import { PrimaryButton } from './components/Button';

const App = () => {
  return (
    <div>
      <Button text="普通按钮" />
      <PrimaryButton text="主要按钮" />
    </div>
  );
};
 

3. 数据管理:Props 与 State 核心

3.1 Props:组件间单向传参

3.1.1 核心特性

  1. 作用:实现 父子组件单向数据传递(父传子,子组件无法直接修改 props)
  2. 只读性:props 是只读的,修改 props 会触发 React 警告(遵循单向数据流原则)
  3. 传递内容:可传递基本类型(字符串、数字、布尔等)、引用类型(对象、数组)、函数(实现子传父)、JSX 元素(插槽)

3.1.2 基本使用

jsx
 
 
 
 
 
// 子组件:接收并使用 props
const UserCard = ({ name, age, isAdult }) => {
  return (
    <div style={{ padding: '16px', border: '1px solid #eee' }}>
      <h3>姓名:{name}</h3>
      <p>年龄:{age}</p>
      <p>是否成年:{isAdult ? '是' : '否'}</p>
    </div>
  );
};

// 父组件:传递 props 给子组件
const Parent = () => {
  return (
    <div>
      {/* 传递基本类型 props */}
      <UserCard name="张三" age={25} isAdult={true} />
      {/* 传递引用类型 props */}
      <UserCard name="李四" age={17} isAdult={false} />
    </div>
  );
};
 

3.1.3 Props 默认值

两种设置方式:函数参数默认值(推荐)、defaultProps(兼容类组件)
jsx
 
 
 
 
 
// 方式1:函数参数默认值(推荐,简洁)
const Greeting = ({ name = '匿名用户', message = '欢迎使用 React' }) => {
  return <p>{name}:{message}</p>;
};

// 方式2:defaultProps(旧版,兼容类组件)
const Greeting = ({ name, message }) => {
  return <p>{name}:{message}</p>;
};
Greeting.defaultProps = {
  name: '匿名用户',
  message: '欢迎使用 React'
};

// 使用:不传递 props 则使用默认值
<Greeting /> 
 

3.1.4 Props 类型校验

使用 prop-types 库校验 props 类型,避免传参错误(开发环境生效,生产环境可移除)
bash
 
运行
 
 
 
 
# 安装 prop-types
npm install prop-types --save
 
jsx
 
 
 
 
 
import PropTypes from 'prop-types';

const UserCard = ({ name, age, isAdult, hobbies }) => {
  return (
    <div>
      <h3>{name}</h3>
      <p>年龄:{age}</p>
      <p>爱好:{hobbies.join(', ')}</p>
    </div>
  );
};

// 定义 props 类型校验
UserCard.propTypes = {
  name: PropTypes.string.isRequired, // 字符串类型,必填
  age: PropTypes.number, // 数字类型
  isAdult: PropTypes.bool, // 布尔类型
  hobbies: PropTypes.arrayOf(PropTypes.string) // 字符串数组类型
};

export default UserCard;
 

3.2 State:组件内部可变状态

3.2.1 核心特性

  1. 作用:管理组件自身的可变数据,状态更新会触发组件重新渲染
  2. 不可直接修改:必须通过状态更新函数修改,直接修改不会触发渲染
  3. 异步更新:React 会批量优化状态更新,无法在 setState 后立即获取最新状态
  4. 函数式更新:当新状态依赖上一次状态时,需使用函数形式更新

3.2.2 函数组件中使用 useState(核心 Hook)

jsx
 
 
 
 
 
import React, { useState } from 'react';

const Counter = () => {
  // 声明状态:[当前状态, 状态更新函数] = useState(初始值)
  const [count, setCount] = useState(0); // 数字状态
  const [user, setUser] = useState({ name: '张三', age: 20 }); // 对象状态
  const [todos, setTodos] = useState(['学习 React', '掌握 Hooks']); // 数组状态

  // 1. 基本状态更新(不依赖上一次状态)
  const increment = () => {
    setCount(count + 1); // 正确
    // count += 1; // 错误:直接修改状态,不触发渲染
  };

  // 2. 函数式状态更新(依赖上一次状态,推荐异步场景)
  const incrementAsync = () => {
    setTimeout(() => {
      setCount(prevCount => prevCount + 1); // 正确:使用上一次状态
    }, 1000);
  };

  // 3. 对象状态更新(需展开原有对象,保持不可变性)
  const updateUser = () => {
    setUser(prevUser => ({
      ...prevUser, // 展开原有属性
      age: prevUser.age + 1 // 修改需要更新的属性
    }));
  };

  // 4. 数组状态更新(需返回新数组,保持不可变性)
  const addTodo = () => {
    setTodos(prevTodos => [...prevTodos, '学习 React Router']); // 正确:添加元素
    // setTodos(todos.push('学习 React Router')); // 错误:push 修改原数组
  };

  return (
    <div style={{ padding: '16px' }}>
      <p>计数:{count}</p>
      <button onClick={increment}>点击加1</button>
      <button onClick={incrementAsync}>异步加1</button>
      
      <p>用户名:{user.name},年龄:{user.age}</p>
      <button onClick={updateUser}>增加年龄</button>
      
      <p>待办列表:</p>
      <ul>
        {todos.map((todo, index) => (
          <li key={index}>{todo}</li>
        ))}
      </ul>
      <button onClick={addTodo}>添加待办</button>
    </div>
  );
};

export default Counter;
 

3.2.3 Props 与 State 核心区别

对比维度 Props State
数据来源 父组件传递 组件内部初始化 / 生成
可修改性 只读,不可直接修改 可修改(通过状态更新函数)
作用范围 父子组件间共享 组件内部私有
触发渲染 父组件修改 props,子组件重新渲染 组件内部调用 setState,自身重新渲染
核心原则 单向数据流 状态不可变

4. 钩子函数:Hooks 全解析

4.1 Hooks 核心规则

  1. 只能在 函数组件 或 自定义 Hooks 中调用(不能在类组件、普通函数中调用)
  2. 只能在组件的 顶层作用域 调用(不能在 if/for 循环、嵌套函数中调用)
  3. 可通过 ESLint 插件 eslint-plugin-react-hooks 强制遵守规则

4.2 核心内置 Hooks

4.2.1 useState:状态管理(已在 3.2.2 详细讲解)

4.2.2 useEffect:副作用处理

核心特性
  1. 作用:处理函数组件中的 副作用(数据请求、DOM 操作、定时器 / 订阅、本地存储操作等)
  2. 执行时机:由第二个参数(依赖数组)控制
  3. 清除副作用:返回一个清理函数,在组件卸载或依赖更新前执行(防止内存泄漏)
依赖数组与执行时机对应表
依赖数组写法 执行时机 对应类组件生命周期
不传递依赖 组件每次渲染后都执行 componentDidUpdate + componentDidMount
传递空数组 [] 仅组件 挂载时 执行一次 componentDidMount
传递具体依赖 [a, b] 仅在依赖项(a 或 b)发生变化时执行 自定义生命周期(依赖更新时)
完整示例
jsx
 
 
 
 
 
import React, { useState, useEffect } from 'react';

const EffectDemo = () => {
  const [count, setCount] = useState(0);
  const [data, setData] = useState(null);

  // 示例1:依赖 count,count 变化时执行
  useEffect(() => {
    console.log(`count 更新为:${count}`);
    // 清理函数:count 变化前/组件卸载时执行
    return () => {
      console.log(`清理:count 即将更新`);
    };
  }, [count]);

  // 示例2:空依赖,仅挂载时执行(数据请求)
  useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await fetch('https://jsonplaceholder.typicode.com/todos/1');
        const result = await res.json();
        setData(result);
      } catch (err) {
        console.error('请求失败:', err);
      }
    };
    fetchData();

    // 清理函数:组件卸载时执行(清除定时器/订阅等)
    return () => {
      console.log('组件卸载,清理副作用');
    };
  }, []);

  // 示例3:无依赖,每次渲染后执行(不推荐,易导致无限循环)
  // useEffect(() => {
  //   console.log('组件每次渲染后执行');
  // });

  return (
    <div>
      <p>count:{count}</p>
      <button onClick={() => setCount(count + 1)}>加1</button>
      {data && (
        <div>
          <h3>请求数据:</h3>
          <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
      )}
    </div>
  );
};

export default EffectDemo;
 

4.2.3 useRef:DOM 引用 & 持久化数据

核心特性
  1. 两种核心用途:
    • 获取 DOM 元素 / 组件实例(需通过 ref 属性绑定)
    • 保存组件生命周期内的持久化数据(组件重新渲染时,数据不丢失,且修改不会触发组件渲染)
  2. 核心属性:current,用于存储引用数据 / DOM 实例
完整示例
jsx
 
 
 
 
 
import React, { useState, useEffect, useRef } from 'react';

const RefDemo = () => {
  const [inputValue, setInputValue] = useState('');
  // 1. 获取 DOM 元素引用
  const inputRef = useRef(null);
  // 2. 保存持久化数据(计时器ID,组件渲染不丢失)
  const timerRef = useRef(null);
  // 3. 保存上一次的 inputValue
  const prevValueRef = useRef('');

  // 挂载后自动聚焦输入框
  useEffect(() => {
    inputRef.current.focus(); // 通过 current 获取 DOM 实例
  }, []);

  // 监听 inputValue 变化,保存上一次值
  useEffect(() => {
    prevValueRef.current = inputValue; // 修改 current 不触发组件渲染
  }, [inputValue]);

  // 启动定时器
  const startTimer = () => {
    timerRef.current = setInterval(() => {
      console.log('定时器运行中...');
    }, 1000);
  };

  // 清除定时器
  const clearTimer = () => {
    clearInterval(timerRef.current);
  };

  return (
    <div style={{ padding: '16px' }}>
      {/* 绑定 ref 到输入框 */}
      <input
        ref={inputRef}
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="自动聚焦输入框"
      />
      <p>当前值:{inputValue}</p>
      <p>上一次值:{prevValueRef.current}</p>
      <button onClick={startTimer}>启动定时器</button>
      <button onClick={clearTimer} style={{ marginLeft: '10px' }}>清除定时器</button>
    </div>
  );
};

export default RefDemo;
 

4.2.4 useContext:跨组件通信

核心特性
  1. 作用:配合 createContext,解决 多层级非父子组件通信 问题,无需逐层传递 props(避免 props 透传)
  2. 核心流程:创建 Context → 提供 Context 数据(Provider)→ 消费 Context 数据(useContext)
完整示例
jsx
 
 
 
 
 
import React, { createContext, useContext, useState } from 'react';

// 1. 创建 Context(可设置默认值,非必须)
const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {} });

// 2. 提供 Context 数据(Provider,通常在根组件/父组件中使用)
const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');

  // 切换主题的方法
  const toggleTheme = () => {
    setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
  };

  // 传递给子组件的数据(可传递状态和方法)
  const contextValue = {
    theme,
    toggleTheme
  };

  return (
    <ThemeContext.Provider value={contextValue}>
      {children}
    </ThemeContext.Provider>
  );
};

// 3. 消费 Context 数据(任意子组件,无需逐层传参)
const ThemeButton = () => {
  // 使用 useContext 获取 Context 数据
  const { theme, toggleTheme } = useContext(ThemeContext);

  // 根据主题设置样式
  const buttonStyle = {
    padding: '8px 16px',
    border: 'none',
    borderRadius: '4px',
    backgroundColor: theme === 'light' ? '#fff' : '#333',
    color: theme === 'light' ? '#333' : '#fff',
    cursor: 'pointer'
  };

  return (
    <button style={buttonStyle} onClick={toggleTheme}>
      当前主题:{theme},点击切换
    </button>
  );
};

// 4. 全局使用
const App = () => {
  return (
    <ThemeProvider>
      <div style={{ padding: '16px' }}>
        <ThemeButton />
      </div>
    </ThemeProvider>
  );
};

export default App;
 

4.3 自定义 Hooks

4.3.1 核心特性

  1. 作用:抽取组件中可复用的逻辑,实现逻辑复用(替代类组件中的 HOC/Render Props)
  2. 命名规范:必须以 use 开头(如 useTimer、useFetch),便于 React 识别 Hooks 规则
  3. 返回值:灵活自定义(可返回状态、方法、对象等)
  4. 特性:内部可调用其他内置 Hooks,遵循 Hooks 核心规则

4.3.2 实战示例 1:useFetch(通用数据请求 Hook)

jsx
 
 
 
 
 
// ./hooks/useFetch.js
import { useState, useEffect } from 'react';

// 自定义 Hook:通用数据请求
const useFetch = (url, options = {}) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    // 取消请求的控制器
    const controller = new AbortController();
    const signal = controller.signal;

    // 异步请求函数
    const fetchData = async () => {
      try {
        setLoading(true);
        const res = await fetch(url, { ...options, signal });
        if (!res.ok) {
          throw new Error(`请求失败:${res.status} ${res.statusText}`);
        }
        const result = await res.json();
        setData(result);
        setError(null);
      } catch (err) {
        // 排除取消请求的错误
        if (err.name !== 'AbortError') {
          setError(err.message);
          setData(null);
        }
      } finally {
        // 排除取消请求的情况,更新 loading 状态
        if (!signal.aborted) {
          setLoading(false);
        }
      }
    };

    fetchData();

    // 清理函数:组件卸载/依赖更新时取消请求
    return () => {
      controller.abort();
    };
  }, [url, options]);

  // 返回状态和数据
  return { data, loading, error };
};

export default useFetch;
 
jsx
 
 
 
 
 
// 使用 useFetch Hook
import useFetch from './hooks/useFetch';

const FetchDemo = () => {
  // 调用自定义 Hook
  const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');

  if (loading) {
    return <p>加载中...</p>;
  }

  if (error) {
    return <p style={{ color: 'red' }}>错误:{error}</p>;
  }

  return (
    <div>
      <h3>数据请求结果:</h3>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
};

export default FetchDemo;
 

4.3.3 实战示例 2:useTimer(定时器 Hook)

jsx
 
 
 
 
 
// ./hooks/useTimer.js
import { useState, useEffect, useRef } from 'react';

// 自定义 Hook:定时器
const useTimer = (initialSeconds = 0) => {
  const [seconds, setSeconds] = useState(initialSeconds);
  const timerRef = useRef(null);

  // 启动定时器
  const startTimer = () => {
    if (timerRef.current) return; // 防止重复启动
    timerRef.current = setInterval(() => {
      setSeconds(prev => prev + 1);
    }, 1000);
  };

  // 暂停定时器
  const pauseTimer = () => {
    clearInterval(timerRef.current);
    timerRef.current = null;
  };

  // 重置定时器
  const resetTimer = () => {
    clearInterval(timerRef.current);
    timerRef.current = null;
    setSeconds(initialSeconds);
  };

  // 清理函数:组件卸载时清除定时器
  useEffect(() => {
    return () => {
      clearInterval(timerRef.current);
    };
  }, []);

  // 返回状态和方法
  return { seconds, startTimer, pauseTimer, resetTimer };
};

export default useTimer;
 
jsx
 
 
 
 
 
// 使用 useTimer Hook
import useTimer from './hooks/useTimer';

const TimerDemo = () => {
  const { seconds, startTimer, pauseTimer, resetTimer } = useTimer(0);

  return (
    <div style={{ padding: '16px' }}>
      <h3>计时器:{seconds} 秒</h3>
      <button onClick={startTimer} style={{ marginRight: '10px' }}>启动</button>
      <button onClick={pauseTimer} style={{ marginRight: '10px' }}>暂停</button>
      <button onClick={resetTimer}>重置</button>
    </div>
  );
};

export default TimerDemo;
 

5. 组件通信:全场景解决方案

5.1 父子组件通信

5.1.1 父传子:Props(已在 3.1 详细讲解)

5.1.2 子传父:Props 传递回调函数

核心思路:父组件定义回调函数并通过 props 传递给子组件,子组件调用该回调函数并传递数据。
jsx
 
 
 
 
 
// 子组件
const ChildInput = ({ onValueChange }) => {
  const handleInput = (e) => {
    // 调用父组件传递的回调函数,传递输入框值
    onValueChange(e.target.value);
  };

  return (
    <input
      type="text"
      placeholder="输入内容传递给父组件"
      onChange={handleInput}
    />
  );
};

// 父组件
const Parent = () => {
  const [inputValue, setInputValue] = useState('');

  // 定义回调函数,接收子组件传递的数据
  const handleValueChange = (value) => {
    setInputValue(value);
  };

  return (
    <div style={{ padding: '16px' }}>
      <p>父组件接收的值:{inputValue}</p>
      {/* 传递回调函数给子组件 */}
      <ChildInput onValueChange={handleValueChange} />
    </div>
  );
};
 

5.2 兄弟组件通信

核心思路:通过 父组件中转(兄弟组件 A → 父组件 → 兄弟组件 B)
jsx
 
 
 
 
 
// 兄弟组件A:传递数据给父组件
const BrotherA = ({ onSendMsg }) => {
  const handleClick = () => {
    onSendMsg('我是兄弟组件A传递的消息');
  };

  return <button onClick={handleClick}>给兄弟组件B传值</button>;
};

// 兄弟组件B:接收父组件传递的数据
const BrotherB = ({ msg }) => {
  return <p>兄弟组件B接收的消息:{msg}</p>;
};

// 父组件:中转数据
const Parent = () => {
  const [msg, setMsg] = useState('');

  const handleMsgChange = (data) => {
    setMsg(data);
  };

  return (
    <div style={{ padding: '16px' }}>
      <BrotherA onSendMsg={handleMsgChange} />
      <BrotherB msg={msg} />
    </div>
  );
};
 

5.3 跨层级组件通信(非父子 / 多层级)

5.3.1 Context API(已在 4.2.4 详细讲解,适合中小型项目)

5.3.2 全局状态管理库(适合中大型项目,如 Redux Toolkit、Zustand,见第 7 章)

5.4 非关联组件通信(无任何层级关系)

  1. 全局状态管理库(推荐,如 Redux Toolkit、Zustand)
  2. 事件总线(不推荐,易维护性差,如 mitt 库)
bash
 
运行
 
 
 
 
# 安装 mitt
npm install mitt --save
 
jsx
 
 
 
 
 
// ./utils/eventBus.js
import mitt from 'mitt';

// 创建事件总线实例
const eventBus = mitt();

export default eventBus;
 
jsx
 
 
 
 
 
// 组件A:发送事件
import eventBus from './utils/eventBus';

const ComponentA = () => {
  const handleSend = () => {
    // 发送事件,传递数据
    eventBus.emit('customEvent', '组件A发送的消息');
  };

  return <button onClick={handleSend}>发送事件</button>;
};
 
jsx
 
 
 
 
 
// 组件B:接收事件
import { useEffect } from 'react';
import eventBus from './utils/eventBus';

const ComponentB = () => {
  useEffect(() => {
    // 监听事件
    const handler = (data) => {
      console.log('组件B接收的事件数据:', data);
    };
    eventBus.on('customEvent', handler);

    // 清理函数:组件卸载时移除监听
    return () => {
      eventBus.off('customEvent', handler);
    };
  }, []);

  return <p>组件B:监听事件</p>;
};
 

6. 路由管理:React Router v6 实战

React Router v6 是 React 官方推荐的路由库,用于构建单页应用(SPA)的页面跳转与路由管理。

6.1 安装 React Router v6

bash
 
运行
 
 
 
 
# 安装核心包(浏览器端使用)
npm install react-router-dom --save
 

6.2 基本使用:路由配置与跳转

6.2.1 根组件配置(BrowserRouter)

jsx
 
 
 
 
 
// src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom'; // 导入 BrowserRouter
import App from './App';
import './index.css';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    {/* 用 BrowserRouter 包裹根组件,提供路由上下文 */}
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);
 

6.2.2 路由配置(Routes、Route)

Routes 替代 v5 中的 Switch,Route 必须包裹在 Routes 中,element 属性指定路由对应组件。
jsx
 
 
 
 
 
// src/App.jsx
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import NotFound from './pages/NotFound';

const App = () => {
  return (
    <div style={{ padding: '16px' }}>
      {/* 导航链接(Link 替代 a 标签,无页面刷新) */}
      <nav style={{ marginBottom: '20px' }}>
        <Link to="/" style={{ marginRight: '20px' }}>首页</Link>
        <Link to="/about">关于我们</Link>
      </nav>

      {/* 路由配置 */}
      <Routes>
        {/* 首页路由(默认路由) */}
        <Route path="/" element={<Home />} />
        {/* 关于我们路由 */}
        <Route path="/about" element={<About />} />
        {/* 404 路由(匹配所有未定义路由,需放在最后) */}
        <Route path="*" element={<NotFound />} />
      </Routes>
    </div>
  );
};

export default App;
 

6.2.3 页面组件示例

jsx
 
 
 
 
 
// src/pages/Home.jsx
const Home = () => {
  return <h2>首页:欢迎学习 React Router v6</h2>;
};

export default Home;
 
jsx
 
 
 
 
 
// src/pages/About.jsx
const About = () => {
  return <h2>关于我们:React 路由实战</h2>;
};

export default About;
 
jsx
 
 
 
 
 
// src/pages/NotFound.jsx
const NotFound = () => {
  return <h2 style={{ color: 'red' }}>404:页面不存在</h2>;
};

export default NotFound;
 

6.3 路由跳转:编程式导航

使用 useNavigate Hook 实现编程式跳转(替代 v5 中的 useHistory)。
jsx
 
 
 
 
 
import { useNavigate } from 'react-router-dom';

const Home = () => {
  // 获取 navigate 函数
  const navigate = useNavigate();

  // 跳转到关于我们页面
  const goToAbout = () => {
    navigate('/about'); // 普通跳转
    // navigate('/about', { replace: true }); // 替换历史记录(无法返回上一页)
    // navigate(-1); // 返回上一页
  };

  return (
    <div>
      <h2>首页:欢迎学习 React Router v6</h2>
      <button onClick={goToAbout} style={{ marginTop: '10px' }}>
        跳转到关于我们
      </button>
    </div>
  );
};

export default Home;
 

6.4 路由参数:动态路由与参数获取

6.4.1 动态路由配置

jsx
 
 
 
 
 
// src/App.jsx
import { Routes, Route, Link } from 'react-router-dom';
import User from './pages/User';

// 导航链接
<Link to="/user/1001">用户1001</Link>

// 路由配置(:id 为动态参数)
<Routes>
  <Route path="/user/:id" element={<User />} />
</Routes>
 

6.4.2 获取动态参数(useParams)

jsx
 
 
 
 
 
// src/pages/User.jsx
import { useParams } from 'react-router-dom';

const User = () => {
  // 获取动态路由参数
  const { id } = useParams();

  return <h2>用户页面:用户ID为 {id}</h2>;
};

export default User;
 

6.4.3 获取查询参数(useSearchParams)

jsx
 
 
 
 
 
// 导航链接:带查询参数
<Link to="/user/1001?name=张三&age=25">用户1001(带查询参数)</Link>
 
jsx
 
 
 
 
 
// src/pages/User.jsx
import { useParams, useSearchParams } from 'react-router-dom';

const User = () => {
  const { id } = useParams();
  // 获取查询参数(类似 useState,返回 [查询参数对象, 设置查询参数函数])
  const [searchParams, setSearchParams] = useSearchParams();

  // 获取单个查询参数
  const name = searchParams.get('name');
  const age = searchParams.get('age');

  // 修改查询参数
  const updateSearchParams = () => {
    setSearchParams({ name: '李四', age: 26 });
  };

  return (
    <div>
      <h2>用户页面:用户ID为 {id}</h2>
      <p>姓名:{name}</p>
      <p>年龄:{age}</p>
      <button onClick={updateSearchParams} style={{ marginTop: '10px' }}>
        修改查询参数
      </button>
    </div>
  );
};

export default User;
 

6.5 嵌套路由

核心思路:父路由组件中使用 <Outlet /> 作为子路由的占位符,配置子路由时路径继承父路由路径。

6.5.1 路由配置

jsx
 
 
 
 
 
// src/App.jsx
import { Routes, Route, Link } from 'react-router-dom';
import Dashboard from './pages/Dashboard';
import Home from './pages/Home';
import About from './pages/About';
import NotFound from './pages/NotFound';

const App = () => {
  return (
    <div style={{ padding: '16px' }}>
      <nav style={{ marginBottom: '20px' }}>
        <Link to="/" style={{ marginRight: '20px' }}>首页</Link>
        <Link to="/about" style={{ marginRight: '20px' }}>关于我们</Link>
        <Link to="/dashboard">控制台</Link>
      </nav>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        {/* 父路由:控制台 */}
        <Route path="/dashboard" element={<Dashboard />}>
          {/* 子路由:默认子路由(index 为 true) */}
          <Route index element={<p>请选择控制台子菜单</p>} />
          {/* 子路由:用户管理 */}
          <Route path="user" element={<p>用户管理页面</p>} />
          {/* 子路由:订单管理 */}
          <Route path="order" element={<p>订单管理页面</p>} />
        </Route>
        <Route path="*" element={<NotFound />} />
      </Routes>
    </div>
  );
};

export default App;
 

6.5.2 父路由组件(使用 Outlet 占位)

jsx
 
 
 
 
 
// src/pages/Dashboard.jsx
import { Link, Outlet } from 'react-router-dom';

const Dashboard = () => {
  return (
    <div>
      <h2>控制台</h2>
      {/* 子导航 */}
      <nav style={{ margin: '10px 0', borderBottom: '1px solid #eee', paddingBottom: '10px' }}>
        <Link to="user" style={{ marginRight: '20px' }}>用户管理</Link>
        <Link to="order">订单管理</Link>
      </nav>
      {/* 子路由占位符:子路由组件将渲染在这里 */}
      <Outlet />
    </div>
  );
};

export default Dashboard;
 

6.6 路由守卫(权限控制)

核心思路:封装私有路由组件,判断用户权限,有权限则渲染目标组件,无权限则跳转到登录页。
jsx
 
 
 
 
 
// src/components/PrivateRoute.jsx
import { Navigate, Outlet } from 'react-router-dom';

// 私有路由组件
const PrivateRoute = () => {
  // 模拟用户登录状态(实际项目中从本地存储/全局状态获取)
  const isLogin = localStorage.getItem('isLogin') === 'true';

  // 已登录:渲染子路由(Outlet);未登录:跳转到登录页
  return isLogin ? <Outlet /> : <Navigate to="/login" replace />;
};

export default PrivateRoute;
 
jsx
 
 
 
 
 
// src/App.jsx
import { Routes, Route } from 'react-router-dom';
import PrivateRoute from './components/PrivateRoute';
import Dashboard from './pages/Dashboard';
import Login from './pages/Login';

// 路由配置
<Routes>
  {/* 私有路由:需要登录才能访问 */}
  <Route element={<PrivateRoute />}>
    <Route path="/dashboard" element={<Dashboard />}>
      <Route index element={<p>请选择控制台子菜单</p>} />
      <Route path="user" element={<p>用户管理页面</p>} />
      <Route path="order" element={<p>订单管理页面</p>} />
    </Route>
  </Route>
  {/* 登录页 */}
  <Route path="/login" element={<Login />} />
</Routes>
 
jsx
 
 
 
 
 
// src/pages/Login.jsx
import { useNavigate } from 'react-router-dom';

const Login = () => {
  const navigate = useNavigate();

  // 模拟登录
  const handleLogin = () => {
    localStorage.setItem('isLogin', 'true');
    navigate('/dashboard'); // 登录成功后跳转到控制台
  };

  return (
    <div style={{ padding: '16px' }}>
      <h2>登录页</h2>
      <button onClick={handleLogin}>模拟登录</button>
    </div>
  );
};

export default Login;
 

7. 状态管理:从内置方案到主流库

7.1 内置方案:useState + useContext(适合中小型项目)

已在 4.2.4(useContext)详细讲解,核心优势:无需额外安装依赖,简单易用。

7.2 Redux Toolkit(RTK,适合中大型项目,官方推荐)

Redux Toolkit 是 Redux 官方推出的简化工具,解决了传统 Redux 样板代码多、配置复杂的问题。

7.2.1 安装依赖

bash
 
运行
 
 
 
 
npm install @reduxjs/toolkit react-redux --save
 

7.2.2 核心概念

  1. configureStore:创建 Redux Store,简化配置(内置中间件、DevTools)
  2. createSlice:创建切片,封装 state、reducers、actions
  3. Provider:在 React 应用中提供 Store 上下文
  4. useSelector:获取 Store 中的状态
  5. useDispatch:获取 Dispatch 函数,用于分发 Action

7.2.3 步骤 1:创建 Store

jsx
 
 
 
 
 
// src/store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterSlice from './slices/counterSlice';
import userSlice from './slices/userSlice';

// 创建 Store
export const store = configureStore({
  reducer: {
    // 注册切片:counter 和 user
    counter: counterSlice.reducer,
    user: userSlice.reducer
  }
});

export default store;
 

7.2.4 步骤 2:创建 Slice(计数器切片)

jsx
 
 
 
 
 
// src/store/slices/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

// 创建切片
const counterSlice = createSlice({
  name: 'counter', // 切片名称(用于 Action 类型前缀)
  initialState: { // 初始状态
    value: 0
  },
  reducers: { //  reducer 函数(修改状态)
    increment: (state) => {
      // RTK 内置 Immer 库,可直接修改状态(无需返回新状态)
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      // action.payload 为传递的参数
      state.value += action.payload;
    }
  }
});

// 导出 Action 创建函数
export const { increment, decrement, incrementByAmount } = counterSlice.actions;

export default counterSlice;
 

7.2.5 步骤 3:创建 Slice(用户切片)

jsx
 
 
 
 
 
// src/store/slices/userSlice.js
import { createSlice } from '@reduxjs/toolkit';

const userSlice = createSlice({
  name: 'user',
  initialState: {
    name: '张三',
    age: 20,
    isLogin: false
  },
  reducers: {
    login: (state) => {
      state.isLogin = true;
    },
    logout: (state) => {
      state.isLogin = false;
    },
    updateUserInfo: (state, action) => {
      // 更新用户信息
      state.name = action.payload.name;
      state.age = action.payload.age;
    }
  }
});

export const { login, logout, updateUserInfo } = userSlice.actions;

export default userSlice;
 

7.2.6 步骤 4:在 React 应用中注入 Store

jsx
 
 
 
 
 
// src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux'; // 导入 Provider
import store from './store'; // 导入 Store
import App from './App';
import './index.css';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    {/* 用 Provider 包裹根组件,注入 Store */}
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);
 

7.2.7 步骤 5:在组件中使用 Store

jsx
 
 
 
 
 
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from './store/slices/counterSlice';
import { login, logout, updateUserInfo } from './store/slices/userSlice';

const ReduxDemo = () => {
  // 1. 获取 Store 中的状态(useSelector)
  const counterValue = useSelector((state) => state.counter.value);
  const userInfo = useSelector((state) => state.user);

  // 2. 获取 Dispatch 函数(useDispatch)
  const dispatch = useDispatch();

  return (
    <div style={{ padding: '16px' }}>
      <h2>Redux Toolkit 示例</h2>
      <h3>计数器:{counterValue}</h3>
      <button onClick={() => dispatch(increment())} style={{ marginRight: '10px' }}>
        加1
      </button>
      <button onClick={() => dispatch(decrement())} style={{ marginRight: '10px' }}>
        减1
      </button>
      <button onClick={() => dispatch(incrementByAmount(5))}>
        加5
      </button>

      <div style={{ marginTop: '20px' }}>
        <h3>用户信息:</h3>
        <p>姓名:{userInfo.name}</p>
        <p>年龄:{userInfo.age}</p>
        <p>登录状态:{userInfo.isLogin ? '已登录' : '未登录'}</p>
        <button onClick={() => dispatch(login())} style={{ marginRight: '10px' }}>
          登录
        </button>
        <button onClick={() => dispatch(logout())} style={{ marginRight: '10px' }}>
          登出
        </button>
        <button onClick={() => dispatch(updateUserInfo({ name: '李四', age: 25 }))}>
          更新用户信息
        </button>
      </div>
    </div>
  );
};

export default ReduxDemo;
 

7.3 Zustand(轻量型状态管理,适合中小型项目,推荐)

Zustand 是一款轻量、简洁的状态管理库,无需 Provider 包裹,API 简洁,性能优秀。

7.3.1 安装依赖

bash
 
运行
 
 
 
 
npm install zustand --save
 

7.3.2 基本使用

jsx
 
 
 
 
 
// src/store/useStore.js
import { create } from 'zustand';

// 创建 Store
const useStore = create((set) => ({
  // 状态
  counter: 0,
  user: {
    name: '张三',
    age: 20
  },
  // 修改状态的方法(set 用于更新状态)
  increment: () => set((state) => ({ counter: state.counter + 1 })),
  decrement: () => set((state) => ({ counter: state.counter - 1 })),
  incrementByAmount: (amount) => set((state) => ({ counter: state.counter + amount })),
  updateUser: (userInfo) => set((state) => ({ user: { ...state.user, ...userInfo } }))
}));

export default useStore;
 
jsx
 
 
 
 
 
// 在组件中使用
import useStore from './store/useStore';

const ZustandDemo = () => {
  // 1. 获取单个状态(组件仅在该状态变化时重新渲染)
  const counter = useStore((state) => state.counter);
  const user = useStore((state) => state.user);

  // 2. 获取修改状态的方法
  const increment = useStore((state) => state.increment);
  const decrement = useStore((state) => state.decrement);
  const incrementByAmount = useStore((state) => state.incrementByAmount);
  const updateUser = useStore((state) => state.updateUser);

  return (
    <div style={{ padding: '16px' }}>
      <h2>Zustand 示例</h2>
      <h3>计数器:{counter}</h3>
      <button onClick={increment} style={{ marginRight: '10px' }}>加1</button>
      <button onClick={decrement} style={{ marginRight: '10px' }}>减1</button>
      <button onClick={() => incrementByAmount(5)}>加5</button>

      <div style={{ marginTop: '20px' }}>
        <h3>用户信息:</h3>
        <p>姓名:{user.name}</p>
        <p>年龄:{user.age}</p>
        <button onClick={() => updateUser({ name: '李四', age: 25 })}>
          更新用户信息
        </button>
      </div>
    </div>
  );
};

export default ZustandDemo;
 

8. 样式解决方案:多种 React 样式实现

8.1 行内样式(简单场景,不推荐复杂样式)

已在 2.1.1 详细讲解,优势:简单直接,无样式冲突;劣势:不支持伪类、媒体查询,样式冗余。

8.2 全局 CSS(全局样式,适合基础样式 / 重置样式)

css
 
 
 
 
 
/* src/index.css(全局样式) */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: Arial, sans-serif;
  background-color: #f5f5f5;
}

.container {
  width: 1200px;
  margin: 0 auto;
}
 
jsx
 
 
 
 
 
// 在组件中使用
const App = () => {
  return <div className="container">全局样式示例</div>;
};
 

8.3 CSS 模块(CSS Modules,推荐,避免样式冲突)

CSS 模块会自动为样式类名添加唯一哈希值,避免全局样式冲突。

8.3.1 基本使用

css
 
 
 
 
 
/* src/components/Button.module.css(文件名必须以 .module.css 结尾) */
.button {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.primary {
  background-color: #1890ff;
  color: #fff;
}

.secondary {
  background-color: #f5f5f5;
  color: #333;
}
 
jsx
 
 
 
 
 
// src/components/Button.jsx
import styles from './Button.module.css'; // 导入 CSS 模块

const Button = ({ type = 'primary', children, onClick }) => {
  return (
    <button
      // 拼接类名
      className={`${styles.button} ${styles[type]}`}
      onClick={onClick}
    >
      {children}
    </button>
  );
};

export default Button;
 

8.4 Sass/Less(CSS 预处理器,支持变量、嵌套等特性)

8.4.1 安装 Sass(以 Sass 为例,Less 类似)

bash
 
运行
 
 
 
 
# Vite 项目(内置 Sass 支持,直接安装依赖即可)
npm install sass --save-dev

# CRA 项目(内置 Sass 支持,直接安装依赖即可)
npm install node-sass --save-dev
 

8.4.2 基本使用

scss
 
 
 
 
 
// src/components/Card.module.scss
$primary-color: #1890ff;
$border-radius: 4px;
$padding: 16px;

.card {
  padding: $padding;
  border: 1px solid #eee;
  border-radius: $border-radius;

  // 嵌套样式
  .title {
    font-size: 18px;
    color: $primary-color;
    margin-bottom: 10px;
  }

  .content {
    font-size: 14px;
    color: #333;
  }
}
 
jsx
 
 
 
 
 
// src/components/Card.jsx
import styles from './Card.module.scss';

const Card = ({ title, children }) => {
  return (
    <div className={styles.card}>
      <div className={styles.title}>{title}</div>
      <div className={styles.content}>{children}</div>
    </div>
  );
};

export default Card;
 

8.5 Styled Components(CSS-in-JS,支持组件化样式、动态样式)

8.5.1 安装依赖

bash
 
运行
 
 
 
 
npm install styled-components --save
 

8.5.2 基本使用

jsx
 
 
 
 
 
import styled from 'styled-components';

// 创建 styled 组件
const StyledButton = styled.button`
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  background-color: ${props => props.primary ? '#1890ff' : '#f5f5f5'};
  color: ${props => props.primary ? '#fff' : '#333'};
  &:hover {
    opacity: 0.9;
  }
`;

// 创建嵌套组件
const Card = styled.div`
  padding: 16px;
  border: 1px solid #eee;
  border-radius: 4px;

  .title {
    font-size: 18px;
    color: #1890ff;
    margin-bottom: 10px;
  }
`;

// 在组件中使用
const StyledDemo = () => {
  return (
    <div style={{ padding: '16px' }}>
      <StyledButton primary>主要按钮</StyledButton>
      <StyledButton style={{ marginLeft: '10px' }}>次要按钮</StyledButton>
      <Card style={{ marginTop: '20px' }}>
        <div className="title">Card 标题</div>
        <div>Card 内容</div>
      </Card>
    </div>
  );
};

export default StyledDemo;
 

8.6 Tailwind CSS(原子化 CSS,高效开发,推荐)

8.6.1 安装与配置(Vite 项目)

bash
 
运行
 
 
 
 
# 1. 安装依赖
npm install -D tailwindcss postcss autoprefixer

# 2. 初始化配置文件
npx tailwindcss init -p
 
js
 
 
 
 
 
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}", // 匹配所有 src 下的 React 文件
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
 
css
 
 
 
 
 
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
 

8.6.2 基本使用

jsx
 
 
 
 
 
const TailwindDemo = () => {
  return (
    <div className="container mx-auto p-4">
      <h2 className="text-2xl font-bold text-blue-600 mb-4">Tailwind CSS 示例</h2>
      <button className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 mr-2">
        主要按钮
      </button>
      <button className="bg-gray-200 text-gray-800 px-4 py-2 rounded hover:bg-gray-300">
        次要按钮
      </button>
      <div className="mt-4 p-4 border border-gray-200 rounded">
        <div className="text-lg font-semibold text-blue-600 mb-2">Card 标题</div>
        <div className="text-gray-700">Card 内容</div>
      </div>
    </div>
  );
};

export default TailwindDemo;
 

9. 性能优化:组件与项目级优化技巧

9.1 组件重渲染优化

9.1.1 React.memo:缓存函数组件(浅比较 props)

用于优化函数组件的不必要重渲染,当组件的 props 未发生变化时,复用上次渲染的结果。
jsx
 
 
 
 
 
import React, { memo, useState } from 'react';

// 使用 React.memo 包裹组件,缓存渲染结果
const Child = memo(({ name }) => {
  console.log('Child 组件重渲染了');
  return <p>子组件:{name}</p>;
});

const Parent = () => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('张三');

  return (
    <div>
      <p>父组件:{count}</p>
      <button onClick={() => setCount(count + 1)}>加1</button>
      {/* 当 count 变化时,name 未变化,Child 组件不会重渲染 */}
      <Child name={name} />
    </div>
  );
};
 

9.1.2 useMemo:缓存计算结果

用于优化昂贵的计算操作,仅当依赖项发生变化时,才重新计算结果。
jsx
 
 
 
 
 
import React, { useState, useMemo } from 'react';

const ExpensiveCalculation = ({ list }) => {
  // 昂贵的计算:过滤并排序数组(仅当 list 变化时重新计算)
  const sortedList = useMemo(() => {
    console.log('执行昂贵计算');
    return list.filter(item => item > 10).sort((a, b) => a - b);
  }, [list]);

  return (
    <div>
      <p>排序后的列表:{sortedList.join(', ')}</p>
    </div>
  );
};

const Parent = () => {
  const [count, setCount] = useState(0);
  const [list, setList] = useState([20, 5, 15, 30, 8]);

  return (
    <div>
      <p>计数:{count}</p>
      <button onClick={() => setCount(count + 1)}>加1</button>
      {/* count 变化时,sortedList 不会重新计算 */}
      <ExpensiveCalculation list={list} />
    </div>
  );
};
 

9.1.3 useCallback:缓存函数引用

用于优化传递给子组件的函数 props,避免因函数引用变化导致子组件不必要重渲染(需配合 React.memo 使用)。
jsx
 
 
 
 
 
import React, { useState, memo, useCallback } from 'react';

const Child = memo(({ onButtonClick }) => {
  console.log('Child 组件重渲染了');
  return <button onClick={onButtonClick}>子组件按钮</button>;
});

const Parent = () => {
  const [count, setCount] = useState(0);

  // 使用 useCallback 缓存函数引用(仅当依赖项变化时更新函数)
  const handleButtonClick = useCallback(() => {
    console.log('按钮被点击');
  }, []); // 空依赖:函数引用永久缓存

  return (
    <div>
      <p>计数:{count}</p>
      <button onClick={() => setCount(count + 1)}>加1</button>
      {/* handleButtonClick 引用不变,Child 组件不会重渲染 */}
      <Child onButtonClick={handleButtonClick} />
    </div>
  );
};
 

9.2 列表渲染优化

列表渲染是 React 应用中高频场景,不合理的列表渲染会导致大量 DOM 操作和不必要的重渲染,需重点优化。

9.2.1 合理使用 key(核心优化点)

key 是 React 用于识别列表元素唯一性的标识,用于优化 Diff 算法的执行效率,避免不必要的 DOM 增删改操作。
用法 场景 优缺点
使用唯一 ID(推荐) 列表元素有唯一标识(如接口返回的 id、uuid) 优点:React 能精准识别元素变化,仅更新 / 删除对应 DOM,性能最优
 
缺点:需确保 ID 唯一性
使用 index(不推荐) 列表无唯一 ID、仅静态展示(不排序 / 不删除 / 不新增) 优点:使用简单,无需额外数据
 
缺点:当列表发生排序、删除、新增(非尾部)操作时,会导致大量元素 key 变化,触发不必要的 DOM 重渲染,甚至导致组件状态错乱
示例代码
jsx
 
 
 
 
 
// 推荐:使用唯一 ID 作为 key
const TodoList = ({ todos }) => {
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id} style={{ padding: '8px', borderBottom: '1px solid #eee' }}>
          <span>{todo.text}</span>
          <button style={{ marginLeft: '10px', color: 'red' }}>删除</button>
        </li>
      ))}
    </ul>
  );
};

// 不推荐:使用 index 作为 key(存在排序/删除/非尾部新增场景)
const BadTodoList = ({ todos }) => {
  return (
    <ul>
      {todos.map((todo, index) => (
        <li key={index}> {/* 风险:列表变化时导致性能问题/状态错乱 */}
          {todo.text}
        </li>
      ))}
    </ul>
  );
};
 

9.2.2 虚拟列表(解决长列表性能问题)

当列表数据量极大(如 1000+ 条)时,直接渲染所有 DOM 元素会导致页面卡顿、加载缓慢,虚拟列表 仅渲染当前可视区域的 DOM 元素,滚动时动态替换可视区域内容,大幅减少 DOM 数量。
推荐使用成熟库:react-window(轻量)、react-virtualized(功能全面),以下以 react-window 为例。
步骤 1:安装依赖
bash
 
运行
 
 
 
 
npm install react-window --save
 
步骤 2:基本使用(固定高度列表)
jsx
 
 
 
 
 
import React from 'react';
import { FixedSizeList as List } from 'react-window';

// 模拟 10000 条长列表数据
const bigListData = Array.from({ length: 10000 }, (_, index) => ({
  id: index + 1,
  content: `长列表项 ${index + 1}`
}));

// 列表项组件
const ListItem = ({ index, style }) => {
  const item = bigListData[index];
  // 必须将 style 传递给列表项容器(用于定位可视区域元素)
  return (
    <div style={{ ...style, padding: '12px', borderBottom: '1px solid #eee' }}>
      {item.id} - {item.content}
    </div>
  );
};

// 虚拟列表组件
const VirtualListDemo = () => {
  return (
    <div style={{ width: '400px', height: '400px', border: '1px solid #eee' }}>
      <List
        height={400} // 列表可视区域高度
        width="100%" // 列表可视区域宽度
        itemCount={bigListData.length} // 总数据量
        itemSize={44} // 每个列表项的高度(固定)
      >
        {ListItem}
      </List>
    </div>
  );
};

export default VirtualListDemo;
 

9.3 项目级性能优化

组件级优化聚焦单个组件的渲染效率,项目级优化覆盖打包、资源、网络等全局层面,进一步提升应用加载速度和运行性能。

9.3.1 打包优化

(1)代码分割(Code Splitting)
将应用代码拆分为多个小块(chunk),仅在用户需要时加载对应模块(如路由懒加载),减少首屏加载体积。
jsx
 
 
 
 
 
import { Routes, Route, Link, lazy, Suspense } from 'react-router-dom';

// 动态导入页面组件(代码分割),替代静态 import
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Dashboard = lazy(() => import('./pages/Dashboard'));

// 加载中占位组件
const Loading = () => <p>页面加载中...</p>;

const App = () => {
  return (
    <div>
      <nav>
        <Link to="/">首页</Link>
        <Link to="/about">关于我们</Link>
        <Link to="/dashboard">控制台</Link>
      </nav>

      {/* Suspense 包裹懒加载组件,指定加载中占位内容 */}
      <Suspense fallback={<Loading />}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/dashboard" element={<Dashboard />} />
        </Routes>
      </Suspense>
    </div>
  );
};
 
js
 
 
 
 
 
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    rollupOptions: {
      output: {
        // 按模块类型分割打包(第三方依赖、业务代码、公共代码)
        manualChunks: {
          vendor: ['react', 'react-dom', 'react-router-dom'], // 第三方依赖打包为 vendor.chunk.js
          utils: ['lodash', 'axios'] // 工具库打包为 utils.chunk.js
        }
      }
    }
  }
});
 
(2)Tree Shaking(摇树优化)
剔除代码中未被使用的死代码(如未调用的函数、未引用的变量),减少打包体积。
json
 
 
 
 
 
{
  "sideEffects": [
    "*.css", // CSS 文件有副作用(样式注入),不进行 Tree Shaking
    "*.scss"
  ]
}
 
(3)资源压缩
js
 
 
 
 
 
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    terserOptions: {
      compress: {
        drop_console: true, // 生产环境移除 console.log
        drop_debugger: true // 生产环境移除 debugger
      }
    }
  }
});
 

9.3.2 静态资源优化

(1)图片优化
(2)字体优化
html
 
预览
 
 
 
 
<!-- index.html -->
<link
  rel="preload"
  href="/fonts/Roboto-Regular.woff2"
  as="font"
  type="font/woff2"
  crossorigin
/>
 

9.3.3 网络优化

(1)接口缓存
jsx
 
 
 
 
 
// 基于 useFetch 扩展缓存功能
import { useState, useEffect, useRef } from 'react';

const useFetchWithCache = (url, options = {}, cacheKey = null, cacheTime = 3600000) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const cacheRef = useRef({}); // 内存缓存容器

  useEffect(() => {
    // 优先从内存缓存获取数据
    if (cacheKey && cacheRef.current[cacheKey]) {
      const cacheData = cacheRef.current[cacheKey];
      // 检查缓存是否过期
      if (Date.now() - cacheData.time < cacheTime) {
        setData(cacheData.data);
        setLoading(false);
        return;
      }
    }

    // 从本地存储获取缓存(持久化缓存)
    if (cacheKey && localStorage.getItem(cacheKey)) {
      const cacheData = JSON.parse(localStorage.getItem(cacheKey));
      if (Date.now() - cacheData.time < cacheTime) {
        setData(cacheData.data);
        setLoading(false);
        // 更新内存缓存
        cacheRef.current[cacheKey] = cacheData;
        return;
      }
    }

    // 无缓存时发起请求
    const fetchData = async () => {
      try {
        const res = await fetch(url, options);
        const result = await res.json();
        setData(result);
        // 存入缓存
        if (cacheKey) {
          const cacheData = { data: result, time: Date.now() };
          cacheRef.current[cacheKey] = cacheData;
          localStorage.setItem(cacheKey, JSON.stringify(cacheData));
        }
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url, options, cacheKey, cacheTime]);

  return { data, loading, error };
};

export default useFetchWithCache;
 
(2)请求合并与防抖 / 节流
jsx
 
 
 
 
 
import { useState } from 'react';
import { debounce } from 'lodash';

const SearchInput = () => {
  const [keyword, setKeyword] = useState('');

  // 防抖处理:输入停止 500ms 后执行搜索
  const handleSearch = debounce(async (key) => {
    if (!key.trim()) return;
    const res = await fetch(`https://api.example.com/search?keyword=${key}`);
    const data = await res.json();
    console.log('搜索结果:', data);
  }, 500);

  const handleInputChange = (e) => {
    const value = e.target.value;
    setKeyword(value);
    handleSearch(value); // 触发防抖函数
  };

  return (
    <input
      type="text"
      value={keyword}
      onChange={handleInputChange}
      placeholder="输入关键词搜索"
    />
  );
};
 

10. 工程化:规范、打包与部署

10.1 代码规范

统一的代码规范能提升团队协作效率,减少代码冲突和 Bug,核心依赖 ESLint(语法检查)和 Prettier(代码格式化)。

10.1.1 安装与配置(Vite + React)

bash
 
运行
 
 
 
 
# 安装开发依赖
npm install -D eslint prettier eslint-plugin-react eslint-plugin-react-hooks eslint-config-prettier
 
(1)ESLint 配置(.eslintrc.cjs)
js
 
 
 
 
 
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:react/jsx-runtime', // 适配 React 17+ JSX 转换
    'plugin:react-hooks/recommended',
    'prettier' // 禁用 ESLint 中与 Prettier 冲突的规则
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  plugins: ['react', 'react-hooks'],
  rules: {
    // React 相关规则
    'react/prop-types': 'off', // 关闭 Props 类型校验(若使用 TypeScript 可开启)
    'react/react-in-jsx-scope': 'off', // React 17+ 无需手动导入 React
    // 自定义规则
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'indent': ['error', 2], // 缩进 2 个空格
    'quotes': ['error', 'single'], // 使用单引号
    'semi': ['error', 'always'] // 语句末尾必须加分号
  },
  settings: {
    react: {
      version: 'detect' // 自动检测 React 版本
    }
  }
};
 
(2)Prettier 配置(.prettierrc)
json
 
 
 
 
 
{
  "singleQuote": true,
  "semi": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100,
  "bracketSpacing": true
}
 
(3)忽略文件(.eslintignore & .prettierignore)
plaintext
 
 
 
 
 
# .eslintignore & .prettierignore 通用配置
node_modules/
dist/
public/
vite.config.js
 
(4)添加 npm 脚本
json
 
 
 
 
 
{
  "scripts": {
    "lint": "eslint . --ext .js,.jsx",
    "lint:fix": "eslint . --ext .js,.jsx --fix",
    "format": "prettier --write \"**/*.{js,jsx,css,md}\""
  }
}
 

10.1.2 提交规范

使用 husky(Git 钩子工具)和 lint-staged(暂存区文件校验),确保提交的代码符合规范,避免不合格代码提交到仓库。
bash
 
运行
 
 
 
 
# 安装依赖
npm install -D husky lint-staged @commitlint/cli @commitlint/config-conventional
 
(1)启用 husky
bash
 
运行
 
 
 
 
npx husky install
# 添加 npm 脚本,自动启用 husky
npm set-script prepare "husky install"
 
(2)添加 pre-commit 钩子(提交前校验代码)
bash
 
运行
 
 
 
 
npx husky add .husky/pre-commit "npx lint-staged"
 
(3)配置 lint-staged(.lintstagedrc.json)
json
 
 
 
 
 
{
  "*.{js,jsx}": ["eslint --fix", "prettier --write"],
  "*.{css,scss}": ["prettier --write"],
  "*.md": ["prettier --write"]
}
 
(4)配置 commit 信息规范(.commitlintrc.cjs)
js
 
 
 
 
 
module.exports = {
  extends: ['@commitlint/config-conventional']
};
 
(5)添加 commit-msg 钩子(校验提交信息)
bash
 
运行
 
 
 
 
npx husky add .husky/commit-msg "npx --no -- commitlint --edit $1"
 
(6)提交信息格式
遵循 Conventional Commits 规范,格式:type(scope): subject

10.2 打包优化

已在 9.3.1 中详细讲解(代码分割、Tree Shaking、资源压缩),此处补充不同脚手架的打包细节。

10.2.1 Vite 打包

bash
 
运行
 
 
 
 
# 生产环境打包
npm run build
# 预览打包结果
npm run preview
 
js
 
 
 
 
 
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  base: '/react-demo/', // 公共路径(部署到子路径时配置,如 GitHub Pages)
  build: {
    outDir: 'build', // 自定义输出目录(默认 dist)
    assetsDir: 'static' // 静态资源目录(默认 assets)
  }
});
 

10.2.2 Create React App 打包

bash
 
运行
 
 
 
 
# 生产环境打包
npm run build
# 预览打包结果(需额外安装 serve)
npm install -g serve
serve -s build
 

10.3 部署方案

React 应用分为 静态应用(纯前端,无服务端逻辑)和 SSR 应用(服务端渲染,如 Next.js),此处重点讲解静态应用部署。

10.3.1 静态部署(推荐)

(1)免费平台部署(快速上线)
(2)云服务器部署(阿里云 / 腾讯云)
  1. 打包应用:npm run build
  2. 将打包后的 dist/build 目录上传到服务器(通过 FTP/SSH)
  3. 配置 Nginx 反向代理(以阿里云 CentOS 为例):
nginx
 
 
 
 
 
# 编辑 Nginx 配置文件
vi /etc/nginx/conf.d/react-demo.conf

# 配置内容
server {
  listen 80;
  server_name 你的域名(如 demo.com);

  # 指向打包后的静态资源目录
  root /usr/local/react-demo/dist;
  index index.html;

  # 解决单页应用路由刷新 404 问题
  location / {
    try_files $uri $uri/ /index.html;
  }

  # 静态资源缓存配置
  location ~* \.(js|css|png|jpg|gif|woff2|woff)$ {
    expires 7d; # 缓存 7 天
    add_header Cache-Control "public, max-age=604800";
  }
}

# 重启 Nginx
nginx -s reload
 

10.3.2 SSR 应用部署(Next.js)

  1. 打包应用:npm run build
  2. 部署方式:
    • Vercel(推荐):一键关联 GitHub 仓库,自动部署
    • 云服务器:启动 Node 服务(npm start),配置 Nginx 反向代理转发请求到 Node 服务端口

11. 实战案例:整合核心知识点

11.1 案例介绍

实现一个 简易商品列表应用,整合 React 核心语法、React Router v6、Zustand 状态管理、Tailwind CSS 样式、性能优化等知识点,功能包括:
  1. 路由跳转(首页 / 商品列表 / 商品详情)
  2. 商品列表展示(虚拟列表优化)
  3. 商品搜索(防抖优化)
  4. 购物车功能(全局状态管理)
  5. 样式美化(Tailwind CSS)

11.2 核心依赖

bash
 
运行
 
 
 
 
# 核心依赖
npm install react react-dom react-router-dom zustand react-window
# 样式依赖
npm install -D tailwindcss postcss autoprefixer
# 工具依赖
npm install lodash
 

11.3 项目结构

plaintext
 
 
 
 
 
react-product-demo/
├── src/
│   ├── assets/          # 静态资源
│   ├── components/      # 公共组件(Navbar、ProductItem、Cart等)
│   ├── pages/           # 页面组件(Home、ProductList、ProductDetail)
│   ├── store/           # Zustand 状态管理
│   ├── hooks/           # 自定义 Hook(useDebounce、useFetchWithCache)
│   ├── App.jsx          # 根组件
│   ├── main.jsx         # 入口文件
│   └── index.css        # Tailwind CSS 入口
├── tailwind.config.js   # Tailwind CSS 配置
├── vite.config.js       # Vite 配置
└── package.json         # 项目配置
 

11.4 核心代码实现

11.4.1 状态管理(Zustand)

jsx
 
 
 
 
 
// src/store/useProductStore.js
import { create } from 'zustand';

const useProductStore = create((set, get) => ({
  // 商品列表
  products: [],
  // 购物车列表
  cartList: [],
  // 搜索关键词
  searchKeyword: '',
  // 设置商品列表
  setProducts: (products) => set({ products }),
  // 设置搜索关键词
  setSearchKeyword: (keyword) => set({ searchKeyword: keyword }),
  // 添加到购物车
  addToCart: (product) => {
    const cartList = get().cartList;
    const existProduct = cartList.find(item => item.id === product.id);
    if (existProduct) {
      // 已存在则增加数量
      set({
        cartList: cartList.map(item => 
          item.id === product.id ? { ...item, count: item.count + 1 } : item
        )
      });
    } else {
      // 不存在则添加
      set({ cartList: [...cartList, { ...product, count: 1 }] });
    }
  },
  // 从购物车移除
  removeFromCart: (productId) => {
    set({
      cartList: get().cartList.filter(item => item.id !== productId)
    });
  }
}));

export default useProductStore;
 

11.4.2 商品列表页面(含虚拟列表 + 防抖搜索)

jsx
 
 
 
 
 
// src/pages/ProductList.jsx
import { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { FixedSizeList as List } from 'react-window';
import { debounce } from 'lodash';
import useProductStore from '../store/useProductStore';
import useFetchWithCache from '../hooks/useFetchWithCache';

const ProductList = () => {
  const [inputKeyword, setInputKeyword] = useState('');
  const { products, setProducts, setSearchKeyword, addToCart } = useProductStore();
  // 防抖搜索
  const debouncedSearch = debounce((keyword) => {
    setSearchKeyword(keyword);
  }, 500);

  // 请求商品数据(带缓存)
  const { data, loading } = useFetchWithCache(
    'https://fakestoreapi.com/products',
    {},
    'productList',
    3600000
  );

  // 初始化商品列表
  useEffect(() => {
    if (data) {
      setProducts(data);
    }
  }, [data, setProducts]);

  // 处理输入变化
  const handleInputChange = (e) => {
    const value = e.target.value;
    setInputKeyword(value);
    debouncedSearch(value);
  };

  // 过滤商品列表
  const filteredProducts = products.filter(product => 
    product.title.toLowerCase().includes(inputKeyword.toLowerCase())
  );

  // 商品列表项
  const ProductItem = ({ index, style }) => {
    const product = filteredProducts[index];
    return (
      <div style={style} className="p-4 border-b border-gray-200 flex items-center gap-4">
        <Link to={`/product/${product.id}`} className="w-20 h-20 flex-shrink-0">
          <img 
            src={product.image} 
            alt={product.title} 
            className="w-full h-full object-contain"
            loading="lazy"
          />
        </Link>
        <div className="flex-1">
          <Link to={`/product/${product.id}`} className="font-medium text-gray-800 hover:text-blue-600 line-clamp-1">
            {product.title}
          </Link>
          <p className="text-red-600 font-bold mt-1">${product.price.toFixed(2)}</p>
          <button 
            onClick={() => addToCart(product)}
            className="mt-2 px-3 py-1 bg-blue-600 text-white rounded text-sm hover:bg-blue-700"
          >
            加入购物车
          </button>
        </div>
      </div>
    );
  };

  if (loading) {
    return <div className="flex justify-center items-center h-64">加载中...</div>;
  }

  return (
    <div className="container mx-auto p-4">
      <div className="mb-6">
        <input
          type="text"
          placeholder="搜索商品..."
          value={inputKeyword}
          onChange={handleInputChange}
          className="w-full px-4 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
        />
      </div>
      <div className="h-[600px] border border-gray-200 rounded">
        <List
          height={600}
          width="100%"
          itemCount={filteredProducts.length}
          itemSize={120}
        >
          {ProductItem}
        </List>
      </div>
    </div>
  );
};

export default ProductList;
 

11.4.3 路由配置

jsx
 
 
 
 
 
// src/App.jsx
import { Routes, Route, Link, Outlet } from 'react-router-dom';
import Home from './pages/Home';
import ProductList from './pages/ProductList';
import ProductDetail from './pages/ProductDetail';
import Cart from './components/Cart';
import useProductStore from './store/useProductStore';

const Navbar = () => {
  const cartList = useProductStore(state => state.cartList);
  // 计算购物车商品总数
  const cartCount = cartList.reduce((total, item) => total + item.count, 0);

  return (
    <nav className="bg-gray-800 text-white p-4">
      <div className="container mx-auto flex justify-between items-center">
        <div className="flex gap-6">
          <Link to="/" className="hover:text-blue-300">首页</Link>
          <Link to="/products" className="hover:text-blue-300">商品列表</Link>
        </div>
        <div className="relative">
          <Link to="/cart" className="hover:text-blue-300">
            购物车
            {cartCount > 0 && (
              <span className="absolute -top-2 -right-2 bg-red-600 text-white text-xs rounded-full w-5 h-5 flex justify-center items-center">
                {cartCount}
              </span>
            )}
          </Link>
        </div>
      </div>
    </nav>
  );
};

const Layout = () => {
  return (
    <div>
      <Navbar />
      <Outlet /> {/* 子路由占位符 */}
    </div>
  );
};

const App = () => {
  return (
    <Routes>
      <Route element={<Layout />}>
        <Route index element={<Home />} />
        <Route path="/products" element={<ProductList />} />
        <Route path="/product/:id" element={<ProductDetail />} />
        <Route path="/cart" element={<Cart />} />
      </Route>
    </Routes>
  );
};

export default App;
 

11.5 运行与部署

  1. 启动开发服务:npm run dev
  2. 生产环境打包:npm run build
  3. 部署:参考 10.3 节的静态部署方案,可部署到 Netlify/Vercel/ 阿里云服务器

12. 附录:API 速查 & 常见问题

12.1 API 速查

12.1.1 核心 React API

API 用途 示例
React.createElement 创建 React 元素(JSX 编译后调用) React.createElement('div', { className: 'demo' }, '内容')
React.StrictMode 严格模式,检查组件潜在问题(仅开发环境) <React.StrictMode><App /></React.StrictMode>
React.Fragment 空片段,包裹多根节点无额外 DOM <React.Fragment><h1>标题</h1><p>内容</p></React.Fragment>(简写 <>)

12.1.2 核心 Hooks API

Hook 用途 示例
useState 管理组件内部状态 const [count, setCount] = useState(0)
useEffect 处理副作用(数据请求、DOM 操作等) useEffect(() => { /* 副作用逻辑 */ }, [deps])
useRef 获取 DOM 引用 / 保存持久化数据 const inputRef = useRef(null); inputRef.current.focus()
useContext 消费 Context 数据 const theme = useContext(ThemeContext)
useMemo 缓存计算结果 const sortedList = useMemo(() => list.sort(), [list])
useCallback 缓存函数引用 const handleClick = useCallback(() => {}, [])

12.1.3 React Router v6 API

API 用途 示例
BrowserRouter 提供路由上下文(浏览器端) <BrowserRouter><App /></BrowserRouter>
Routes/Route 路由配置容器 / 单个路由 <Routes><Route path="/" element={<Home />} /></Routes>
Link 导航链接(无页面刷新) <Link to="/products">商品列表</Link>
useNavigate 编程式导航 const navigate = useNavigate(); navigate('/products')
useParams 获取动态路由参数 const { id } = useParams()
Outlet 嵌套路由占位符 <Outlet />

12.1.4 Zustand API

API 用途 示例
create 创建 Zustand Store const useStore = create((set) => ({ count: 0, increment: () => set(state => ({ count: state.count + 1 })) }))
useStore 消费 Store 状态 / 方法 const count = useStore(state => state.count); const increment = useStore(state => state.increment)

12.2 常见问题

12.2.1 组件不重新渲染

12.2.2 State 更新异步

12.2.3 路由刷新 404

12.2.4 Props 透传问题

12.2.5 长列表卡顿