React 核心知识点系统总结:从基础语法到高级 API,一篇文章梳理完整学习路线

React 核心知识点系统总结:从基础语法到高级 API,一篇文章梳理完整学习路线

摘要

React 是当前前端开发中非常重要的 UI 库,它的核心思想并不是"记住一堆 API",而是理解 组件化开发、数据驱动视图、单向数据流、状态管理和前端路由 这一整套开发模式。

本文将按照 React 的学习路线,对 React 中的核心知识点进行系统总结,内容包括:

文章目录

  • [React 核心知识点系统总结:从基础语法到高级 API,一篇文章梳理完整学习路线](#React 核心知识点系统总结:从基础语法到高级 API,一篇文章梳理完整学习路线)
  • [一、初识 React](#一、初识 React)
    • [1. React 是什么?](#1. React 是什么?)
    • [2. React 的核心思想](#2. React 的核心思想)
  • [二、React 基础语法](#二、React 基础语法)
  • 三、JSX
    • [1. JSX 是什么?](#1. JSX 是什么?)
    • [2. JSX 的基本规则](#2. JSX 的基本规则)
      • [2.1 必须有一个根节点](#2.1 必须有一个根节点)
      • [2.2 class 要写成 className](#2.2 class 要写成 className)
      • [2.3 style 要写成对象](#2.3 style 要写成对象)
      • [2.4 JSX 中可以写表达式,不能直接写语句](#2.4 JSX 中可以写表达式,不能直接写语句)
  • 四、组件
    • [1. 什么是组件?](#1. 什么是组件?)
    • [2. 函数组件](#2. 函数组件)
    • [3. 组件命名规则](#3. 组件命名规则)
  • 五、事件绑定
    • [1. 基本事件绑定](#1. 基本事件绑定)
    • [2. 事件传参](#2. 事件传参)
  • 六、条件渲染
    • [1. 三元表达式](#1. 三元表达式)
    • [2. && 写法](#2. && 写法)
    • [3. 提前 return](#3. 提前 return)
  • 七、列表渲染
    • [1. 使用 map 渲染列表](#1. 使用 map 渲染列表)
    • [2. key 的作用](#2. key 的作用)
  • [八、props 与 state](#八、props 与 state)
    • [1. props](#1. props)
    • [2. state](#2. state)
    • [3. state 不能直接修改](#3. state 不能直接修改)
    • [4. props 和 state 的区别](#4. props 和 state 的区别)
  • 九、组件通信
    • [1. 父传子](#1. 父传子)
    • [2. 子传父](#2. 子传父)
    • [3. 兄弟组件通信](#3. 兄弟组件通信)
    • [4. 跨层级通信](#4. 跨层级通信)
  • 十、Hooks
    • [1. useState](#1. useState)
    • [2. useEffect](#2. useEffect)
    • [3. useEffect 的依赖数组](#3. useEffect 的依赖数组)
      • [3.1 空数组](#3.1 空数组)
      • [3.2 不传依赖数组](#3.2 不传依赖数组)
      • [3.3 有依赖项](#3.3 有依赖项)
    • [4. 清理副作用](#4. 清理副作用)
    • [5. useRef](#5. useRef)
      • [5.1 获取 DOM](#5.1 获取 DOM)
      • [5.2 保存不会触发重新渲染的数据](#5.2 保存不会触发重新渲染的数据)
    • [6. useMemo](#6. useMemo)
    • [7. useCallback](#7. useCallback)
    • [8. 自定义 Hook](#8. 自定义 Hook)
  • 十一、Redux
    • [1. Redux 核心概念](#1. Redux 核心概念)
    • [2. Redux Toolkit](#2. Redux Toolkit)
    • [3. 什么数据适合放 Redux?](#3. 什么数据适合放 Redux?)
  • [十二、React Router](#十二、React Router)
    • [1. 基础路由](#1. 基础路由)
    • [2. Link 跳转](#2. Link 跳转)
    • [3. 编程式导航](#3. 编程式导航)
    • [4. 动态路由](#4. 动态路由)
    • [5. 嵌套路由](#5. 嵌套路由)
    • [6. 路由权限控制](#6. 路由权限控制)
  • [十三、高级 API 和性能优化](#十三、高级 API 和性能优化)
    • [1. React.memo](#1. React.memo)
    • [2. useMemo](#2. useMemo)
    • [3. useCallback](#3. useCallback)
    • [4. forwardRef](#4. forwardRef)
    • [5. useImperativeHandle](#5. useImperativeHandle)
    • [6. lazy 和 Suspense](#6. lazy 和 Suspense)
    • [7. Portal](#7. Portal)
    • [8. Error Boundary](#8. Error Boundary)
  • [十四、React 学习重点总结](#十四、React 学习重点总结)
    • [1. React 的核心不是 API,而是思想](#1. React 的核心不是 API,而是思想)
    • [2. 状态应该放在哪里?](#2. 状态应该放在哪里?)
    • [3. 不要滥用 Redux](#3. 不要滥用 Redux)
    • [4. Hooks 不是越多越好](#4. Hooks 不是越多越好)
    • [5. React 项目开发流程](#5. React 项目开发流程)
  • 十五、结语

本文适合正在学习 React,或者已经学过但知识点比较零散,想系统复盘 React 技术体系的同学阅读。


一、初识 React

1. React 是什么?

React 是一个用于构建用户界面的 JavaScript 库。

它主要负责把数据渲染成页面,并在数据发生变化时,让页面自动更新。

在传统前端开发中,我们经常需要手动操作 DOM:

js 复制代码
const title = document.getElementById("title");
title.innerText = "新的标题";

这种方式在简单页面中没有问题,但当页面交互变复杂、状态变多、DOM 节点变多之后,代码会越来越难维护。

React 的思想是:

text 复制代码
UI = f(state)

也就是说:

页面是状态的结果,状态发生变化后,页面会自动重新渲染。

所以,React 的核心不是"手动修改 DOM",而是"通过数据描述页面"。


2. React 的核心思想

学习 React,最重要的是理解下面几个思想:

核心思想 说明
组件化 把页面拆分成一个个独立组件
声明式开发 只描述页面应该长什么样,不直接操作 DOM
数据驱动视图 数据变化后,页面自动更新
单向数据流 数据通常从父组件传递到子组件
状态不可变 修改状态时创建新数据,而不是直接改原数据

这几个思想贯穿整个 React 学习过程。


二、React 基础语法

React 基础部分是后面学习组件通信、Hooks、Redux、Router 的前提。

React 基础语法主要包括:

  • JSX
  • 组件
  • 事件绑定
  • 条件渲染
  • 列表渲染
  • props
  • state

其中最核心的是 JSX、组件、props、state


三、JSX

1. JSX 是什么?

JSX 是 React 中最常见的语法形式。

它允许我们在 JavaScript 中写类似 HTML 的结构。

示例:

jsx 复制代码
function App() {
  const name = "React";

  return <h1>Hello, {name}</h1>;
}

export default App;

这里的:

jsx 复制代码
{name}

表示在 JSX 中插入 JavaScript 表达式。

需要注意的是,JSX 看起来像 HTML,但它本质上并不是 HTML,而是 JavaScript 的语法扩展,最终会被编译成 JavaScript 代码。


2. JSX 的基本规则

2.1 必须有一个根节点

错误写法:

jsx 复制代码
return (
  <h1>标题</h1>
  <p>内容</p>
);

正确写法:

jsx 复制代码
return (
  <div>
    <h1>标题</h1>
    <p>内容</p>
  </div>
);

如果不想额外生成一个 div,可以使用 Fragment:

jsx 复制代码
return (
  <>
    <h1>标题</h1>
    <p>内容</p>
  </>
);

2.2 class 要写成 className

因为 class 是 JavaScript 的关键字,所以 JSX 中要写成 className

jsx 复制代码
<div className="container">内容</div>

2.3 style 要写成对象

jsx 复制代码
<div style={{ color: "red", fontSize: "20px" }}>
  红色文字
</div>

注意:

CSS 中的 font-size,在 JSX 中要写成小驼峰形式:

js 复制代码
fontSize

2.4 JSX 中可以写表达式,不能直接写语句

可以写:

jsx 复制代码
{age >= 18 ? "成年人" : "未成年人"}

不能直接写:

jsx 复制代码
{if (age >= 18) { return "成年人" }}

因为 if 是语句,不是表达式。

在 JSX 中,常见可以写的内容包括:

jsx 复制代码
{name}
{count + 1}
{isLogin ? "已登录" : "未登录"}
{list.map(item => <li>{item.name}</li>)}

四、组件

1. 什么是组件?

组件是 React 中最核心的单位。

一个页面可以拆分成多个组件:

text 复制代码
App
 ├── Header
 ├── Sidebar
 ├── Main
 │    ├── ArticleList
 │    └── ArticleDetail
 └── Footer

每个组件负责页面中的一部分功能。

组件化的好处是:

  • 代码结构更清晰
  • 功能更容易复用
  • 页面更容易维护
  • 复杂页面可以拆分成多个小模块

2. 函数组件

现在 React 开发中,主流写法是函数组件。

jsx 复制代码
function Header() {
  return <h1>React 学习笔记</h1>;
}

export default Header;

在其他组件中使用:

jsx 复制代码
function App() {
  return (
    <div>
      <Header />
      <p>这是页面内容</p>
    </div>
  );
}

3. 组件命名规则

React 组件名必须首字母大写。

例如:

jsx 复制代码
<Header />

这是自定义组件。

而:

jsx 复制代码
<header />

这是原生 HTML 标签。

React 会通过首字母是否大写,判断这是普通 HTML 标签还是自定义组件。


五、事件绑定

1. 基本事件绑定

React 中事件使用小驼峰命名。

例如:

jsx 复制代码
function App() {
  const handleClick = () => {
    console.log("按钮被点击了");
  };

  return <button onClick={handleClick}>点击</button>;
}

需要注意:

jsx 复制代码
onClick={handleClick}

表示点击时执行函数。

而:

jsx 复制代码
onClick={handleClick()}

表示组件渲染时立即执行函数。

这是初学者非常容易写错的地方。


2. 事件传参

如果事件函数需要传参,可以使用箭头函数包一层。

jsx 复制代码
function App() {
  const handleClick = (id) => {
    console.log("当前 id:", id);
  };

  return <button onClick={() => handleClick(100)}>点击</button>;
}

不能直接写成:

jsx 复制代码
<button onClick={handleClick(100)}>点击</button>

因为这样会在页面渲染时立即执行。


六、条件渲染

条件渲染就是根据不同条件显示不同内容。

1. 三元表达式

jsx 复制代码
function App() {
  const isLogin = true;

  return (
    <div>
      {isLogin ? <span>已登录</span> : <span>未登录</span>}
    </div>
  );
}

三元表达式适合"二选一"的场景。


2. && 写法

如果只需要在条件成立时显示内容,可以使用 &&

jsx 复制代码
{isLogin && <button>退出登录</button>}

含义是:

text 复制代码
isLogin 为 true,显示按钮
isLogin 为 false,不显示按钮

这种写法适合"满足条件才显示"的场景。


3. 提前 return

如果条件逻辑比较复杂,可以提前 return。

jsx 复制代码
function UserInfo({ user }) {
  if (!user) {
    return <div>请先登录</div>;
  }

  return <div>欢迎你,{user.name}</div>;
}

这种写法比在 JSX 中写一堆复杂判断更清晰。


七、列表渲染

1. 使用 map 渲染列表

React 中通常使用 map 渲染列表。

jsx 复制代码
function App() {
  const list = [
    { id: 1, name: "React" },
    { id: 2, name: "Vue" },
    { id: 3, name: "Angular" },
  ];

  return (
    <ul>
      {list.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

2. key 的作用

在列表渲染中,key 非常重要。

key 的作用是帮助 React 识别每一个列表项,从而提高更新效率。

推荐使用唯一 id:

jsx 复制代码
<li key={item.id}>{item.name}</li>

不推荐使用数组下标:

jsx 复制代码
<li key={index}>{item.name}</li>

如果列表会新增、删除、排序,使用 index 作为 key 可能会导致渲染错误或性能问题。


八、props 与 state

props 和 state 是 React 中非常重要的两个概念。

1. props

props 用于父组件向子组件传递数据。

jsx 复制代码
function Child(props) {
  return <div>{props.name}</div>;
}

function App() {
  return <Child name="React" />;
}

也可以使用解构写法:

jsx 复制代码
function Child({ name }) {
  return <div>{name}</div>;
}

props 的特点是:

  • 由父组件传入
  • 子组件只读
  • 子组件不能直接修改 props

2. state

state 是组件内部自己的状态。

函数组件中使用 useState 定义状态。

jsx 复制代码
import { useState } from "react";

function App() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      当前数量:{count}
    </button>
  );
}

这里:

jsx 复制代码
const [count, setCount] = useState(0);

含义是:

内容 说明
count 当前状态值
setCount 修改状态的方法
0 初始值

3. state 不能直接修改

错误写法:

jsx 复制代码
count++;

正确写法:

jsx 复制代码
setCount(count + 1);

如果 state 是对象,也不能直接修改原对象。

错误写法:

jsx 复制代码
user.name = "张三";
setUser(user);

正确写法:

jsx 复制代码
setUser({
  ...user,
  name: "张三",
});

React 强调状态不可变。

修改状态时,应该创建一个新数据,而不是直接修改原数据。


4. props 和 state 的区别

对比项 props state
来源 父组件传入 组件内部定义
是否可修改 子组件不能修改 组件自己可以修改
作用 组件之间传值 管理组件内部状态
更新方式 父组件重新传入 setState / setXxx 修改

简单理解:

props 是外部传进来的数据,state 是组件自己管理的数据。


九、组件通信

React 是单向数据流,数据通常从父组件流向子组件。

常见组件通信方式如下:

通信场景 实现方式
父传子 props
子传父 父组件传函数,子组件调用
兄弟组件通信 状态提升
跨层级通信 Context
全局通信 Redux

1. 父传子

父组件通过 props 把数据传给子组件。

jsx 复制代码
function Child({ title }) {
  return <h2>{title}</h2>;
}

function App() {
  return <Child title="React 学习" />;
}

2. 子传父

子组件不能直接修改父组件的数据。

如果子组件想把数据传给父组件,需要父组件先传一个函数给子组件。

jsx 复制代码
function Child({ onSend }) {
  return (
    <button onClick={() => onSend("来自子组件的数据")}>
      发送数据
    </button>
  );
}

function App() {
  const handleReceive = (data) => {
    console.log("父组件接收到:", data);
  };

  return <Child onSend={handleReceive} />;
}

这个过程可以理解为:

text 复制代码
父组件把函数传给子组件
子组件调用这个函数
调用时把数据作为参数传回父组件

3. 兄弟组件通信

兄弟组件之间不能直接通信。

通常需要把共享状态提升到共同的父组件中。

jsx 复制代码
function A({ setMsg }) {
  return (
    <button onClick={() => setMsg("来自 A 组件的数据")}>
      发送
    </button>
  );
}

function B({ msg }) {
  return <div>B 组件接收到:{msg}</div>;
}

function App() {
  const [msg, setMsg] = useState("");

  return (
    <div>
      <A setMsg={setMsg} />
      <B msg={msg} />
    </div>
  );
}

这种方式叫做状态提升。


4. 跨层级通信

如果组件层级很深,一级一级传 props 会非常麻烦。

例如:

text 复制代码
App → A → B → C → D

如果 App 的数据要传给 D,中间组件都要帮忙传递。

这种情况可以使用 Context。

jsx 复制代码
import { createContext, useContext } from "react";

const UserContext = createContext();

function App() {
  return (
    <UserContext.Provider value="张三">
      <Child />
    </UserContext.Provider>
  );
}

function Child() {
  return <GrandChild />;
}

function GrandChild() {
  const name = useContext(UserContext);

  return <div>当前用户:{name}</div>;
}

Context 适合传递:

  • 用户信息
  • 主题颜色
  • 国际化语言
  • 权限信息
  • 全局配置

但是,如果状态变化频繁,或者业务逻辑复杂,更推荐使用 Redux 等状态管理工具。


十、Hooks

Hooks 是现代 React 开发的核心。

Hooks 让函数组件也可以拥有状态、副作用和逻辑复用能力。

常见 Hooks 包括:

Hook 作用
useState 定义组件状态
useEffect 处理副作用
useRef 获取 DOM 或保存可变数据
useMemo 缓存计算结果
useCallback 缓存函数
useContext 使用 Context 数据
自定义 Hook 复用组件逻辑

1. useState

useState 用于定义组件状态。

jsx 复制代码
const [count, setCount] = useState(0);

完整示例:

jsx 复制代码
function App() {
  const [count, setCount] = useState(0);

  const add = () => {
    setCount(count + 1);
  };

  return <button onClick={add}>{count}</button>;
}

如果新的状态依赖上一次状态,推荐使用函数式写法:

jsx 复制代码
setCount(prev => prev + 1);

这种写法更加稳定。


2. useEffect

useEffect 用来处理副作用。

副作用包括:

  • 请求接口
  • 设置定时器
  • 绑定事件监听
  • 操作 DOM
  • 修改页面标题
  • 订阅数据

基本写法:

jsx 复制代码
useEffect(() => {
  console.log("组件渲染完成");
}, []);

3. useEffect 的依赖数组

3.1 空数组

jsx 复制代码
useEffect(() => {
  console.log("组件挂载时执行一次");
}, []);

表示组件挂载时执行一次。


3.2 不传依赖数组

jsx 复制代码
useEffect(() => {
  console.log("每次组件渲染都会执行");
});

表示每次组件渲染都会执行。


3.3 有依赖项

jsx 复制代码
useEffect(() => {
  console.log("count 变化了");
}, [count]);

表示只有 count 变化时才执行。


4. 清理副作用

如果在组件中使用定时器,需要在组件卸载时清理。

jsx 复制代码
useEffect(() => {
  const timer = setInterval(() => {
    console.log("定时器执行");
  }, 1000);

  return () => {
    clearInterval(timer);
  };
}, []);

return 中的函数就是清理函数。

它会在组件卸载时执行,也会在下一次 effect 执行前执行。


5. useRef

useRef 有两个常见用途。

5.1 获取 DOM

jsx 复制代码
function App() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={focusInput}>聚焦</button>
    </div>
  );
}

5.2 保存不会触发重新渲染的数据

jsx 复制代码
const countRef = useRef(0);

countRef.current++;

修改 ref.current 不会导致组件重新渲染。


6. useMemo

useMemo 用来缓存计算结果。

如果某个计算过程比较耗时,可以使用 useMemo 避免每次渲染都重新计算。

jsx 复制代码
const total = useMemo(() => {
  return list.reduce((sum, item) => sum + item.price, 0);
}, [list]);

只有当 list 变化时,total 才会重新计算。

注意:

useMemo 不是必须到处使用,只有计算成本较高时才有意义。


7. useCallback

useCallback 用来缓存函数引用。

jsx 复制代码
const handleClick = useCallback(() => {
  console.log("点击");
}, []);

它通常和 React.memo 配合使用,减少子组件不必要的重新渲染。


8. 自定义 Hook

自定义 Hook 用于复用逻辑。

例如,封装一个计数器逻辑:

jsx 复制代码
function useCounter() {
  const [count, setCount] = useState(0);

  const add = () => {
    setCount(prev => prev + 1);
  };

  const minus = () => {
    setCount(prev => prev - 1);
  };

  return {
    count,
    add,
    minus,
  };
}

使用:

jsx 复制代码
function App() {
  const { count, add, minus } = useCounter();

  return (
    <div>
      <button onClick={minus}>-</button>
      <span>{count}</span>
      <button onClick={add}>+</button>
    </div>
  );
}

自定义 Hook 的本质是:

把组件中的可复用逻辑抽离出来。


十一、Redux

当项目变复杂后,多个组件之间共享状态会变得困难。

例如:

  • 用户登录信息多个页面都要用
  • 权限信息多个组件都要判断
  • 购物车数据多个页面都要展示
  • 后台管理系统中多个页面共享筛选条件

这时可以使用 Redux。

Redux 是一种全局状态管理方案。

它的核心思想是:

把多个组件都要使用的数据,统一放到一个 store 中管理。


1. Redux 核心概念

Redux 有几个核心概念:

概念 说明
Store 全局状态仓库
State 仓库中的状态数据
Action 描述要做什么事情
Reducer 根据 action 修改 state
Dispatch 触发 action

Redux 的数据流如下:

text 复制代码
组件 dispatch action
        ↓
reducer 根据 action 修改 state
        ↓
store 更新
        ↓
组件重新渲染

2. Redux Toolkit

现在开发中更推荐使用 Redux Toolkit。

它可以减少传统 Redux 中大量模板代码。

示例:

jsx 复制代码
import { createSlice } from "@reduxjs/toolkit";

const counterSlice = createSlice({
  name: "counter",
  initialState: {
    count: 0,
  },
  reducers: {
    add(state) {
      state.count++;
    },
    minus(state) {
      state.count--;
    },
  },
});

export const { add, minus } = counterSlice.actions;
export default counterSlice.reducer;

组件中使用:

jsx 复制代码
import { useSelector, useDispatch } from "react-redux";
import { add, minus } from "./counterSlice";

function App() {
  const count = useSelector(state => state.counter.count);
  const dispatch = useDispatch();

  return (
    <div>
      <button onClick={() => dispatch(minus())}>-</button>
      <span>{count}</span>
      <button onClick={() => dispatch(add())}>+</button>
    </div>
  );
}

3. 什么数据适合放 Redux?

并不是所有状态都应该放进 Redux。

适合放 Redux 的数据:

  • 用户信息
  • 登录状态
  • 权限信息
  • 购物车数据
  • 全局配置
  • 多页面共享的业务状态

不适合放 Redux 的数据:

  • 输入框临时内容
  • 弹窗开关
  • 某个组件内部的小状态
  • 局部 loading
  • 鼠标悬浮状态

简单判断:

text 复制代码
只在当前组件使用:useState
少量跨层级共享:Context
复杂全局共享状态:Redux

十二、React Router

React Router 用于实现前端路由。

在传统网站中,不同页面通常对应不同 HTML 文件。

而在 React 单页应用中,页面切换本质上是组件切换。

例如:

text 复制代码
/          → Home 组件
/about     → About 组件
/detail/1  → Detail 组件

1. 基础路由

jsx 复制代码
import { BrowserRouter, Routes, Route } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}

jsx 复制代码
import { Link } from "react-router-dom";

function Home() {
  return <Link to="/about">跳转到关于页面</Link>;
}

Link 不会刷新整个页面,只会切换前端路由。


3. 编程式导航

有些场景需要在函数中跳转页面,比如登录成功后跳转首页。

jsx 复制代码
import { useNavigate } from "react-router-dom";

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

  const handleLogin = () => {
    navigate("/home");
  };

  return <button onClick={handleLogin}>登录</button>;
}

4. 动态路由

详情页通常需要动态参数。

jsx 复制代码
<Route path="/detail/:id" element={<Detail />} />

获取参数:

jsx 复制代码
import { useParams } from "react-router-dom";

function Detail() {
  const params = useParams();

  return <div>当前 ID:{params.id}</div>;
}

访问:

text 复制代码
/detail/100

可以拿到:

text 复制代码
id = 100

5. 嵌套路由

嵌套路由适合后台管理系统布局。

jsx 复制代码
<Route path="/layout" element={<Layout />}>
  <Route path="home" element={<Home />} />
  <Route path="user" element={<User />} />
  <Route path="setting" element={<Setting />} />
</Route>

Layout 组件中使用:

jsx 复制代码
import { Outlet } from "react-router-dom";

function Layout() {
  return (
    <div>
      <aside>侧边栏</aside>
      <main>
        <Outlet />
      </main>
    </div>
  );
}

Outlet 表示子路由渲染的位置。


6. 路由权限控制

实际项目中,经常需要判断用户是否登录。

如果没有登录,就跳转到登录页。

jsx 复制代码
import { Navigate } from "react-router-dom";

function AuthRoute({ children }) {
  const token = localStorage.getItem("token");

  if (!token) {
    return <Navigate to="/login" />;
  }

  return children;
}

使用:

jsx 复制代码
<Route
  path="/home"
  element={
    <AuthRoute>
      <Home />
    </AuthRoute>
  }
/>

这是前端项目中非常常见的路由鉴权写法。


十三、高级 API 和性能优化

当掌握 React 基础、Hooks、Redux、Router 之后,就需要进一步学习 React 的高级 API。

高级 API 主要解决两个问题:

text 复制代码
1. 性能优化
2. 复杂组件场景

1. React.memo

React.memo 用于避免组件不必要的重新渲染。

jsx 复制代码
const Child = React.memo(function Child({ name }) {
  console.log("Child 渲染了");
  return <div>{name}</div>;
});

如果父组件重新渲染,但传给 Child 的 props 没有变化,那么 Child 不会重新渲染。

适合使用场景:

  • 子组件比较复杂
  • 子组件渲染成本较高
  • props 不经常变化

2. useMemo

useMemo 用于缓存计算结果。

jsx 复制代码
const total = useMemo(() => {
  return list.reduce((sum, item) => sum + item.price, 0);
}, [list]);

适合计算量较大的场景。

但不要滥用 useMemo

如果计算本身很简单,使用 useMemo 反而会增加代码复杂度。


3. useCallback

useCallback 用于缓存函数引用。

jsx 复制代码
const handleClick = useCallback(() => {
  console.log("click");
}, []);

它常用于把函数传给被 React.memo 包裹的子组件。


4. forwardRef

forwardRef 可以让父组件获取子组件内部的 DOM。

jsx 复制代码
const MyInput = forwardRef((props, ref) => {
  return <input ref={ref} />;
});

function App() {
  const inputRef = useRef(null);

  return (
    <div>
      <MyInput ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>
        聚焦
      </button>
    </div>
  );
}

5. useImperativeHandle

useImperativeHandle 可以控制子组件暴露给父组件的方法。

jsx 复制代码
const MyInput = forwardRef((props, ref) => {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => ({
    focus() {
      inputRef.current.focus();
    },
  }));

  return <input ref={inputRef} />;
});

这样父组件只能调用子组件暴露出来的方法,而不是随意操作子组件内部细节。


6. lazy 和 Suspense

lazySuspense 用于组件懒加载。

jsx 复制代码
import { lazy, Suspense } from "react";

const Home = lazy(() => import("./Home"));

function App() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <Home />
    </Suspense>
  );
}

适合用于路由懒加载,可以减少首屏加载体积,提高页面打开速度。


7. Portal

Portal 可以把组件渲染到当前 DOM 层级之外。

常见使用场景:

  • 弹窗
  • 抽屉
  • Tooltip
  • 全局提示

示例:

jsx 复制代码
import { createPortal } from "react-dom";

function Modal() {
  return createPortal(
    <div className="modal">弹窗内容</div>,
    document.body
  );
}

虽然 Modal 写在当前组件中,但它实际会被渲染到 document.body 下。


8. Error Boundary

Error Boundary 用于捕获组件渲染错误,防止整个页面崩溃。

大型项目中,如果某个组件发生错误,可以只显示局部错误提示,而不是整个页面白屏。

需要注意:

Error Boundary 主要使用类组件实现。


十四、React 学习重点总结

1. React 的核心不是 API,而是思想

React 的核心思想包括:

text 复制代码
组件化
声明式开发
数据驱动视图
单向数据流
状态不可变

如果只背 API,而不理解这些思想,写项目时很容易混乱。


2. 状态应该放在哪里?

React 项目中最重要的问题之一是:

这个数据应该放在哪里?

可以按照下面的规则判断:

数据使用范围 推荐方案
只有当前组件使用 useState
父子组件共享 props
兄弟组件共享 状态提升
多层组件共享 Context
多页面复杂共享 Redux

很多 React 项目写乱,不是因为 JSX 不会写,而是因为状态位置设计不合理。


3. 不要滥用 Redux

Redux 很强,但不是所有状态都应该放 Redux。

例如:

jsx 复制代码
const [keyword, setKeyword] = useState("");

这种输入框临时内容,直接放组件内部即可。

Redux 更适合全局共享、跨页面使用、业务复杂的数据。


4. Hooks 不是越多越好

useMemouseCallback 这些 Hook 是优化工具,不是必须到处使用。

更合理的顺序是:

text 复制代码
先写清楚
再考虑复用
最后考虑性能优化

如果组件本身很简单,过度使用优化 Hook 反而会降低代码可读性。


5. React 项目开发流程

一个 React 项目的开发流程可以概括为:

text 复制代码
1. 分析页面结构
2. 拆分组件
3. 设计数据结构
4. 确定状态放在哪里
5. 编写组件
6. 处理组件通信
7. 接入接口请求
8. 接入路由
9. 接入状态管理
10. 做性能优化和代码整理

在真正写代码之前,应该先想清楚:

  • 页面怎么拆
  • 数据从哪里来
  • 状态放在哪里
  • 组件之间如何通信

这比直接上来写 JSX 更重要。


十五、结语

React 的知识点看起来很多,但主线其实非常清楚:

text 复制代码
JSX 是写页面结构的方式
组件是组织页面的单位
props 是父子传值的方式
state 是组件内部状态
Hooks 是函数组件的核心能力
Redux 解决复杂全局状态
React Router 解决页面路由切换
高级 API 解决性能优化和复杂组件场景

如果用一句话总结 React:

React 是一个通过组件化组织页面,通过数据驱动视图,通过单向数据流管理状态的 UI 库。

学习 React 不能只停留在"这个 API 怎么写",更应该理解:

  • 为什么要组件化?
  • 为什么状态不能直接修改?
  • 为什么数据要单向流动?
  • 为什么有些状态适合放 Redux,有些状态只适合放 useState?
  • 为什么需要 useMemo、useCallback 这类优化工具?

当这些问题理解清楚后,React 的知识体系就不会再显得零散。

React 的学习路线可以最终总结为:

text 复制代码
基础语法
  ↓
组件思想
  ↓
数据流
  ↓
Hooks
  ↓
状态管理
  ↓
路由系统
  ↓
高级 API
  ↓
项目实践

只要沿着这条路线学习,就可以从"会写 React"逐渐过渡到"会设计 React 项目"。

相关推荐
Resistance丶未来2 小时前
Coding-Interview-University 学习路径实战评测
人工智能·gpt·学习·github·claude·gemini·kimi
ErizJ2 小时前
Docker | 学习笔记
笔记·学习·docker
ErizJ2 小时前
Kafka | 学习笔记
笔记·学习·kafka
GISer_Jing2 小时前
AI原生前端工程化进阶实践:从流式交互架构到端云协同全链路落地
前端·人工智能·后端·学习
东京老树根2 小时前
SAP学习笔记 - BTP CAP开发02 - Assosication,Composition,?$expand=books
笔记·学习
被考核重击2 小时前
Vue响应式原理(下)
前端·javascript·vue.js
Slow菜鸟10 小时前
AI学习篇(五) | awesome-design-md 使用说明
人工智能·学习
matlab_xiaowang11 小时前
Redux 入门:JavaScript 可预测状态管理库
开发语言·javascript·其他·ecmascript
狐狐生风11 小时前
LangChain 向量存储:Chroma、FAISS
人工智能·python·学习·langchain·faiss·agentai