React 教程:在线运行的实例
免费的 React 19 教程:组件、JSX、props、state、Hook 和性能。每个示例都能在页面上运行,修改代码就能看到组件和控制台随之更新。
开始课程入门
- React 是什么React 是一个用组件构建用户界面的 JavaScript 库。你只需描述在当前数据下屏幕应该显示什么,数据变化时,React 会让页面保持同步。
- 安装 React用 Vite 创建项目来安装 React:检查 Node.js,运行一条创建命令,安装依赖并启动开发服务器。还会介绍生成的文件、生产构建,以及 Create React App 为什么已被弃用。
- JSXJSX 是 JavaScript 的语法扩展,让你在 React 组件里写类似 HTML 的标记。学习它的规则:一个根元素、闭合标签、className、驼峰命名的属性、花括号、内联样式、注释,以及它会编译成什么。
- 组件React 组件就是一个返回 JSX 的 JavaScript 函数。学习如何编写和命名函数组件、把组件组合成一棵树、拆分到多个文件、保持组件纯净,以及组件和元素有什么区别。
- PropsProps 是 React 组件的输入:父组件以 JSX 属性的形式传给子组件的值。学习如何传递和解构 props、设置默认值、传递函数、展开 props,以及为什么 props 是只读的。
- children 属性children 这个 prop 存放的是你写在组件开始标签和结束标签之间的所有内容。学习如何用它构建包装组件和布局组件,用命名 props 传递多个插槽,把 children 当作函数使用,以及什么时候 Children API 并不是合适的工具。
- FragmentReact Fragment 能把多个元素合成一个返回值,又不会往页面里多加节点。学习 <>...</> 简写语法、什么时候需要 <Fragment key>,以及 Fragment 在表格和列表中为什么重要。
- 条件渲染React 中的条件渲染就是普通的 JavaScript:用 if 语句、三元运算符或 && 决定组件返回哪段 JSX。学习每种写法、&& 可能多打印出的 0、返回 null,以及为什么隐藏组件不等于不渲染它。
- 列表与 key在 React 中渲染列表,就是对数组调用 map(),为每一项返回 JSX,并给每一项一个 key prop。学习先 filter 再 map、key 应该从哪里来,以及为什么列表变化时用数组索引做 key 会让各项错乱。
- 事件React 事件是 onClick、onChange 这类接收函数的 props,用户操作时 React 会带着事件对象调用这个函数。学习如何传递处理函数而不是调用它、如何传参、读取 e.target.value 和 e.key、阻止表单刷新页面,以及阻止事件冒泡。
- 样式给 React 组件加样式有几种方式:用 className 配合普通 CSS,用 style prop 写在 JavaScript 中计算出的值,用 CSS Modules 获得作用域隔离的类名,或者用 Tailwind 的工具类。逐一了解每种方式、条件类名,以及各自适用的场景。
state 与表单
- useStateuseState 给组件一个能在重新渲染之间保留的值,以及一个在值变化时重绘屏幕的 setter。学习它的语法、更新函数、state 中的对象和数组,以及为什么刚设置完的值看起来还是旧的。
- 更新数组和对象要修改 React state 中的数组或对象,就创建一个新的,再把它传给 setter。了解如何添加、删除、替换、插入和排序元素,如何更新嵌套对象,以及为什么直接修改 state 不会让界面更新。
- 表单用受控输入框在 React 中构建表单:文本框、textarea、select、复选框和单选按钮,用一个状态对象管理多个字段,用 onSubmit 提交,显示校验错误,以及 React 19 的表单 action。
- 受控与非受控受控输入框的值来自 React 状态,只能通过 onChange 改变。非受控输入框把值保存在 DOM 里,你用 ref 或 FormData 读取它。了解两者的区别、常见警告,以及各自适用的场景。
- 状态提升状态提升是指把 state 从两个组件中移出,放到它们最近的共同父组件里,再由父组件通过 props 把值和修改函数传下去。学习什么时候该提升、如何分三步完成,以及什么时候应该把 state 留在组件内部。
- useReduceruseReducer 存储 state,并把所有更新逻辑集中到一个 reducer 函数中:你派发一个 action,reducer 返回下一个 state。学习它的语法、如何编写纯 reducer、一个待办事项示例、惰性初始化,以及什么时候该选它而不是 useState。
Effect 与 ref
- useEffectuseEffect 在 React 更新屏幕之后运行代码,让组件与 React 之外的东西保持同步:定时器、订阅、事件监听器。学习依赖数组的三种写法、清理函数、无限循环,以及什么时候根本不需要 Effect。
- 获取数据在 React 中获取数据,就是在 useEffect 里发起请求,把加载、错误和数据保存在状态中,并忽略输入变化之后才到达的响应。内容涵盖副作用中的 async/await、AbortController、竞态条件,以及何时改用库。
- useRefuseRef 给组件一个盒子 `{ current }`,它的内容在多次渲染之间保持不变,修改它也不会触发渲染。用它访问 DOM 节点(聚焦、滚动、测量),或者保存定时器 id 以及任何屏幕上不显示的值。
- forwardRefforwardRef 让组件接收父组件传来的 ref,并把它挂到内部的 DOM 节点上。在 React 19 中,函数组件会把 `ref` 当作普通 prop 接收,所以新代码不再需要 forwardRef。看两种写法实际运行,以及 useImperativeHandle 和 TypeScript 类型。
- useLayoutEffectuseLayoutEffect 的用法和 useEffect 一样,但它在 React 更新 DOM 之后、浏览器绘制之前立即运行。用它测量元素并调整布局,避免肉眼可见的闪烁;其他情况仍然用 useEffect。
Hook 与 context
- React Hookshook 是名字以 use 开头的函数,让组件可以使用 state、context、ref 或 effect 等 React 功能。按用途分组了解每个内置 hook、所有 hook 都遵守的两条规则,以及如何编写自己的 hook。
- useContextuseContext 读取父组件提供的值,这样嵌套很深的组件也能拿到它,而无需中间的每个组件都把它作为 prop 往下传。了解 createContext、provider、如何在子组件中更新 context,以及 context 对重新渲染的影响。
- Prop DrillingProp drilling 是指把一个 prop 穿过并不使用它的组件往下传,只为了让更深处的某个组件能用到它。通过可运行的示例看看它是什么样子、应用变大后为什么会成为负担,以及按顺序尝试的解决办法:组合、context,然后是状态管理库。
- 自定义 Hook自定义 Hook 是一个名字以 use 开头、并调用其他 Hook 的函数,让多个组件能复用同一段有状态的逻辑。动手编写 useToggle、useLocalStorage、useDebounce 和 useWindowWidth,并理解为什么每次调用都有自己的状态。
- Hook 规则Hook 有两条规则:只在组件的顶层调用,绝不放在条件、循环或嵌套函数里;只在函数组件或自定义 Hook 中调用。了解 React 为什么要求每次渲染的调用顺序都相同,以及顺序改变时报出的错误该如何修复。
- useIduseId 为每个组件实例返回一个唯一且稳定的 id,即使组件在页面上出现多次,label、input 和 aria-describedby 提示也能互相对应。了解为什么 Math.random 和计数器在服务端渲染时会出问题,以及为什么 useId 不能用作列表的 key。
- useSyncExternalStoreuseSyncExternalStore 让组件订阅 React 之外的数据,比如一个小型 store 模块,或者 navigator.onLine 这样的浏览器 API,并在数据变化时重新渲染。学习 subscribe 和 getSnapshot、为什么快照必须缓存,以及 getServerSnapshot。
渲染与性能
- 渲染React 组件在自己的 state 变化、父组件渲染,或它读取的 context 变化时会重新渲染。了解渲染与提交的区别、虚拟 DOM 的真正含义,以及如何避免不必要的渲染。
- useMemouseMemo 在多次渲染之间缓存计算结果,只在依赖变化时重新计算。学习它的语法,如何为 memo 子组件保持对象引用稳定,以及什么时候不值得用 useMemo。
- useCallbackuseCallback 在多次渲染之间返回同一个函数,直到它的依赖发生变化。只有当这个函数被传给 memo 子组件或用作 Effect 的依赖时,它才有帮助。了解它的语法、与 useMemo 的区别,以及要避免的错误。
- React.memomemo 包裹一个组件,当它的 props 与上次浅比较相等时,React 会跳过它的重新渲染。了解 memo 何时有用、为什么 props 中新的对象和函数会让它失效,以及它拦不住哪些渲染。
- useTransitionuseTransition 把一次状态更新标记为非紧急,React 在后台渲染较慢的部分时,页面依然能及时响应。本文讲解 isPending、startTransition、React 19 的异步 transition,以及它为什么不是防抖。
- useDeferredValueuseDeferredValue 给你一个值的副本,在繁重的渲染期间它允许滞后,这样输入框能保持流畅,而缓慢的列表随后再追上来。了解它的工作原理、React 19 新增的初始值,以及它与 useTransition 和防抖的对比。
- Suspense 和 lazySuspense 会在内部组件还没准备好时显示 fallback,React.lazy 则在组件第一次渲染时才加载它的代码。学习代码分割、嵌套边界、React 19 中 Suspense 与 use() 的配合,以及错误处理。
React 19 与进阶
- React 19React 19 新增了 Actions、useActionState、useOptimistic、use、ref 作为 prop 以及文档元数据,19.2 又加入了 Activity 和 useEffectEvent。逐个运行每项新特性,看看移除了什么,以及如何升级。
- useActionStateuseActionState 包装一个异步 action,保存它上一次返回的值,并告诉你它是否仍在运行。了解它的签名、表单 action、如何返回校验错误,以及如何在表单之外调用它。
- useOptimisticuseOptimistic 在异步 Action 仍在运行时就显示你预期的结果,Action 结束后再回到真实的 state,所以请求失败时界面会自动撤销。学习它的语法、reducer 写法,以及为什么它必须在 Action 内部运行。
- useuse 在渲染期间读取 Promise 或 context 的值。读取 Promise 时,它会挂起直到数据到达,并显示最近的 Suspense 后备内容。与其他 Hook 不同,它可以在 if 语句和循环中运行。
- 错误边界错误边界是一个组件,它能捕获内部组件在渲染时抛出的错误,显示后备 UI,而不是一片空白。了解它能捕获什么、如何用类来编写、如何重置,以及 react-error-boundary 库。
- PortalcreatePortal 能把组件的一部分渲染到另一个 DOM 节点(比如 document.body)中,同时它在 React 树中的位置不变。弹窗、提示框和菜单需要摆脱 overflow hidden 和 z-index 层叠限制时,就用它。
- 严格模式StrictMode 是只在开发环境生效的包裹组件:它会把组件渲染两次,在挂载时按 setup、cleanup、setup 的顺序运行 Effect,并对已废弃的 API 发出警告,让不纯的渲染和缺失的清理尽早暴露出来。在生产环境中它什么也不做。
- 组件生命周期每个 React 组件都会挂载(出现)、更新(再次渲染)和卸载(被移除)。学习每个阶段如何对应到 useEffect,类组件的生命周期方法及其对应的 Hook 写法,以及渲染阶段和提交阶段。
- 类组件类组件是一个继承 React.Component、从 render 方法返回 JSX 的 JavaScript 类。学习 this.props、this.state 和 setState,绑定事件处理函数,生命周期方法,PureComponent,以及如何把类组件改写成函数组件。
对比与面试
- React 面试题约 30 道从入门到进阶的 React 面试题,每道都附有面试官认可的简短答案,那些看比读更容易理解的题目还配有可运行的代码。
- React vs AngularReact 是需要和其他工具搭配使用的 UI 库;Angular 是内置路由、表单、HTTP 和依赖注入的完整框架。并排对比用两者写出的同一个组件。
- React vs VueReact 和 Vue 都是用组件构建用户界面的 JavaScript 工具。它们的区别在于标记写法(JSX 与模板)、响应变化的方式(不可变 state 加重新渲染,与可变的响应式 ref),以及生态中有多少是官方维护的。
- React 与 TypeScript如何用 TypeScript 为 React 应用添加类型:props 和 children、带联合类型和 null 的 useState、用于 DOM 元素的 useRef、事件处理函数、context、泛型组件和原生元素的 props。