React 19.3
概述
此技能包含了 React 19.3 中容易出错的规则:不应存在的 Effect、依赖陷阱、Actions 及其 Transition、Server Components 边界、React Compiler 的采用以及 19 版本中移除或废弃的 API。每个论断都附有对应文档页面 URL。
涵盖版本
React 19.3,即 react.dev 文档所描述的版本。之前的重大版本位于 18.react.dev 及旧站点。https://react.dev/versions
阅读快速入门,然后根据任务打开对应的参考文件。
快速入门
- 仅当需要与 React 无法控制的系统同步时才使用 Effect。在渲染期间派生值,使用
key重置状态,并在事件处理程序中运行由用户触发的逻辑。https://react.dev/learn/you-might-not-need-an-effect - 依赖项遵循代码逻辑:永远不要抑制
react-hooks/exhaustive-deps。要移除依赖项,将对象和函数移到 Effect 内部、使用更新器(updater)或从 Effect 事件中读取值。https://react.dev/learn/removing-effect-dependencies
const onConnected = useEffectEvent(() => {
showNotification('已连接!', theme);
});
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => { onConnected(); });
connection.connect();
return () => connection.disconnect();
}, [roomId]);
https://react.dev/learn/separating-events-from-effects
- Effect 必须经历设置、清理、重新设置的过程:严格模式(Strict Mode)在开发环境中会触发该流程。修复清理函数,切勿使用 ref 防护来隐藏第二次运行。https://react.dev/learn/synchronizing-with-effects
ref是函数组件的一个 prop。渲染<Context value={x}>作为提供者(provider)。ref 回调可以返回其清理函数。https://react.dev/reference/react/useRef 和 https://react.dev/reference/react/createContext 和 https://react.dev/reference/react-dom/components/common- 在
startTransition内部的await之后设置状态不会被视为一个 Transition:需要将其包裹在另一个startTransition中。https://react.dev/reference/react/useTransition - 在使用
<form action>时,useActionState的 reducer 会接收(prevState, formData)。从 Action(<form action>或startTransition)中调用dispatchAction。https://react.dev/reference/react/useActionState useFormStatus仅读取父级<form>:请在子组件中调用它。https://react.dev/reference/react-dom/hooks/useFormStatususe(promise)需要一个缓存的 Promise:在渲染期间创建的 Promise 会在每次渲染时重新创建。切勿使用try/catch包裹use:请使用 Error Boundary。https://react.dev/reference/react/use'use server'用于标记 Server Functions,而非 Server Components(Server Components 没有指令)。验证每个 Server Function 的参数并检查授权。https://react.dev/reference/rsc/server-components 和 https://react.dev/reference/rsc/use-server- 仅浏览器可用的组件:在
<Suspense>边界下使用use(browser())(browser来自react-dom),而不是检查typeof window或使用挂载标志。https://react.dev/reference/react-dom/browser - 使用 React Compiler 时,编写普通代码,仅将
useMemo或useCallback用于精确控制(例如作为 Effect 依赖项)。保留现有的记忆化(memoization)代码。https://react.dev/learn/react-compiler/introduction - 使用
eslint-plugin-react-hooks的recommended配置进行 lint。它包含了编译器规则,因此请移除eslint-plugin-react-compiler。https://react.dev/blog/2025/10/07/react-compiler-1 - 在模块级别定义组件,切勿在另一个组件内部定义。https://react.dev/reference/eslint-plugin-react-hooks/lints/static-components
- 不要在
&&左侧放置数字:count && <p/>会在 count 为 0 时渲染出0。https://react.dev/learn/conditional-rendering
参考文件
| 文件 | 适用场景 |
|---|---|
| references/state.md | useState、更新器、渲染期间设置状态、useReducer、不可变更新、状态结构、key 重置 |
| references/refs-and-context.md | useRef、ref 回调、ref 作为 prop、useImperativeHandle、上下文、useId、useSyncExternalStore |
| references/effects.md | 何时不使用 Effect、useEffect 时序、严格模式清理、数据获取、useLayoutEffect、useInsertionEffect |
| references/effect-dependencies.md | 移除依赖项、useEffectEvent、自定义 Hooks、additionalEffectHooks |
| references/memoization.md | useMemo、useCallback、memo、有无编译器的情况 |
| references/react-compiler.md | 安装、选项、指令、增量采用、调试编译器 |
| references/rules-and-lints.md | React 规则、Hooks 规则、eslint-plugin-react-hooks 规则、严格模式 |
| references/components-and-tooling.md | Keys、条件渲染、Fragment refs、Profiler、act、TypeScript、DevTools |
| references/transitions-and-suspense.md | useTransition、startTransition、useDeferredValue、use、lazy、<Suspense> |
| references/view-transitions-and-activity.md | <ViewTransition>、addTransitionType、<Activity> |
| references/actions-and-optimistic.md | useActionState、useOptimistic、useFormStatus、<form action> |
| references/form-elements-and-events.md | 受控输入、<select>、<textarea>、常见 props、事件、自定义元素 |
| references/server-components.md | Server Components、'use client'、可序列化 props、cache、cacheSignal、taint |
| references/server-functions.md | 'use server'、调用 Server Functions、永久链接(permalink)、安全 |
| references/client-roots-and-hydration.md | createRoot、hydrateRoot、不匹配、错误报告、Error Boundaries |
| references/server-rendering.md | renderToPipeableStream、renderToReadableStream、状态码、prerender、resume |
| references/dom-apis-and-resources.md | browser、createPortal、flushSync、preload、preinit、<img>、<link>、<script>、<title> |
| references/upgrading-to-19.md | 升级步骤、codemods、移除和弃用的 API、TypeScript 变化、19.2 和 19.3 |
| references/legacy-apis.md | Children、cloneElement、类组件、forwardRef、PureComponent |
旧模式
| 旧用法 | 替代方案 | 来源 |
|---|---|---|
forwardRef((props, ref) => ...) | function MyInput({ ref, ...props }) | https://react.dev/reference/react/forwardRef |
<Context.Provider value={x}> | <Context value={x}> | https://react.dev/reference/react/createContext |
<Context.Consumer> render prop | useContext(Context) 或 use(Context) | https://react.dev/reference/react/createContext |
ReactDOM.useFormState | 来自 react 的 useActionState | https://react.dev/blog/2024/12/05/react-19 |
ReactDOM.render、ReactDOM.hydrate | createRoot(el).render()、hydrateRoot | https://react.dev/reference/react-dom |
unmountComponentAtNode | root.unmount() | https://react.dev/reference/react-dom |
findDOMNode | DOM refs | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
字符串 refs、this.refs | Ref 回调或 createRef | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
contextTypes、getChildContext | createContext、static contextType | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
element.ref | element.props.ref | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
react-test-renderer、浅渲染 | Testing Library | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
全局 JSX 命名空间(类型中) | declare module "react" { namespace JSX {} } | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
| UMD 构建 script 标签 | ESM CDN(例如 esm.sh) | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
propTypes | TypeScript | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
函数组件上的 defaultProps | ES 默认参数 | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
import { act } from 'react-dom/test-utils' | import { act } from 'react' | https://react.dev/blog/2024/04/25/react-19-upgrade-guide |
同步 act(() => ...) | await act(async () => ...) | https://react.dev/reference/react/act |
依赖 null 调用的 ref 回调 | 返回一个清理函数 | https://react.dev/reference/react-dom/components/common |
用于 SSR 的 renderToString | renderToPipeableStream 或 renderToReadableStream | https://react.dev/reference/react-dom/server/renderToString |
renderToNodeStream、renderToStaticNodeStream | react-dom/server 流式 API | https://react.dev/reference/react-dom |
| 在服务端抛出异常以跳过 SSR | use(browser()) | https://react.dev/reference/react/Suspense |
在 Effect 中设置 isClient 状态、在渲染中使用 typeof window | 在 <Suspense> 下使用 use(browser()) | https://react.dev/reference/react-dom/browser |
eslint-plugin-react-compiler | eslint-plugin-react-hooks | https://react.dev/blog/2025/10/07/react-compiler-1 |
"use no forget" | "use no memo" | https://react.dev/reference/react-compiler/directives/use-no-memo |
在 @vitejs/plugin-react 6 上使用 react({ babel: { plugins: [...] } }) | 配合 @rolldown/plugin-babel 使用 reactCompilerPreset | https://react.dev/learn/react-compiler/installation |
componentWillMount、componentWillReceiveProps、componentWillUpdate | UNSAFE_ 名称,或页面内的替代方案 | https://react.dev/reference/react/Component |