本章属于 React 教程的核心路线。建议先通读概念模型,再手写最小示例,最后用练习验证自己能否独立复现。
本章目标
本章学习 React DevTools、memo、useMemo、useCallback、Vitest 与 Testing Library。目标是先测量再优化,并用测试守住关键交互。
阅读本章时,请把每个 API 放回“数据如何变成界面、用户操作如何改变数据”的主线中理解。React 的学习重点不是背诵语法,而是建立可预测的渲染模型。
- 识别本章概念在真实组件中的位置
- 能写出一个最小可运行示例
- 能解释常见错误为什么发生
概念模型
性能优化不是默认动作。React DevTools Profiler 帮你确认渲染成本,memo 减少无意义子组件渲染,useMemo 和 useCallback 稳定昂贵计算或函数引用。
你可以把 React 程序看成一棵由组件组成的元素树。每次输入数据、状态或外部系统发生变化,React 会重新计算需要展示的 React element,再用高效的方式更新浏览器中的 DOM。
最小示例
下面的测试用 Testing Library 模拟用户点击,用 Vitest 断言界面变化;组件层面可以用 memo 包裹稳定输入的子组件。
import { memo, useCallback, useMemo, useState } from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { expect, test } from "vitest";
const Total = memo(function Total({ value }: { value: number }) {
return <strong>{value}</strong>;
});
function Counter() {
const [count, setCount] = useState(0);
const doubled = useMemo(() => count * 2, [count]);
const increment = useCallback(() => setCount((value) => value + 1), []);
return <button onClick={increment}>count {doubled}</button>;
}
test("increments counter", async () => {
render(<Counter />);
await userEvent.click(screen.getByRole("button"));
expect(screen.getByText("count 2")).toBeInTheDocument();
});
type LessonNote = { title: string; done: boolean };\nconst note: LessonNote = { title: 'React 教程', done: false };
规则与陷阱
规则的价值在于让多人维护同一个项目时仍能预测行为。下面这些限制看似细碎,实际都在保护组件的输入、输出和生命周期边界。
- 先用 React DevTools 测量,再决定是否优化。
- memo 对频繁变化的 props 没有效果。
- useMemo 不应用来修复副作用问题。
- 测试应面向用户行为,而不是组件内部实现细节。
练习
练习应当先小后大:先验证一个概念,再把它接入完整页面。不要在没有理解失败原因时复制更复杂的代码。
- 用 React DevTools Profiler 记录一次列表渲染。
- 给纯展示组件添加 memo 并比较效果。
- 用 Vitest 和 Testing Library 写一个按钮点击测试。