We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
React 已于近日发布了 v19 的 beta 版本,同时为了帮助后续的 v19 升级,也同时发布了 v18.3.0的正式版, 与 v18.2 版本完全相同,但添加了弃用 API 的警告和其他为 React 19 所需的更改
v19
v18.3.0
v18.2
为了改善打包体积和可以在 JSX 文件中无需手动引入 React,在 2020 年 React 引入了新的 JSX Transform。如果在 React 19 中没有使用这个新的 JSX Transform 会有一个报错提示
React
如果已经使用了新版 JSX Transform 则可以忽略此步骤
npm install react@beta react-dom@beta
如果使用 TypeScript,则还需要更新相关类型包。等到 React 19 发布 release 版本后可以就像往常一样从@types/react和@types/react-dom安装类型包。在当前 beta 版本中需要在package.json为类型包配置overrides 锁定版本以确保不同包中的类型是可用的
@types/react
@types/react-dom
package.json
overrides
{ "dependencies": { "@types/react": "npm:types-react@beta", "@types/react-dom": "npm:types-react-dom@beta" }, "overrides": { "@types/react": "npm:types-react@beta", "@types/react-dom": "npm:types-react-dom@beta" } }
在之前的 React 版本中,渲染过程中抛出的错误会被捕获并重新抛出。在 DEV 模式下,我们还会记录到 console.error,导致出现重复的错误日志。
在 React 19 中,改进了错误处理方式,通过不重新抛出来减少重复信息:
window.reportError
console.error
createRoot
hydrateRoot
const root = createRoot(container, { onUncaughtError: (error, errorInfo) => { // ... log error report }, onCaughtError: (error, errorInfo) => { // ... log error report } });
propTypes
defaultProps
propTypes是用于运行时校验组件 props 的属性,在 Reactv15.5.0已经被标记为废弃,在 v19这个正式删除
Reactv15.5.0
另外函数组件的defaultProps也已经移除(使用 ES6 默认参数替代),由于 class 组件没有相应的 ES6 语法替代因此仍会保留
// Before import PropTypes from 'prop-types'; function Heading({text}) { return <h1>{text}</h1>; } Heading.propTypes = { text: PropTypes.string, }; Heading.defaultProps = { text: 'Hello, world!', };
// After interface Props { text?: string; } function Heading({text = 'Hello, world!'}: Props) { return <h1>{text}</h1>; }
contextTypes
getChildContext
Legacy Context 在2018.10(v16.6.0)已被弃用
Legacy Context 仅适用于使用contextTypes和getChildContext API 的类组件,并由于易于忽略的微妙错误而被contextType替换。在 React 19 中,将删除 Legacy Context 以使 React 更小更快。仍在类组件中使用 Legacy Context,则需要迁移到新的contextType API:
contextType
// Before import PropTypes from 'prop-types'; class Parent extends React.Component { //... static childContextTypes = { foo: PropTypes.string.isRequired, }; getChildContext() { return { foo: 'bar' }; } //... render() { return <Child />; } } class Child extends React.Component { //... static contextTypes = { foo: PropTypes.string.isRequired, }; //... render() { return <div>{this.context.foo}</div>; } }
// After //... const FooContext = React.createContext(); //.... class Parent extends React.Component { render() { return ( <FooContext value='bar'> <Child /> </FooContext> ); } } class Child extends React.Component { //... static contextType = FooContext; //... render() { return <div>{this.context}</div>; } }
字符串 refs 在2018.3(v16.3.0)被弃用
在被替换为 ref 回调方式之前类组件支持字符串 refs,但存在多个缺点。在 React 19 中,将删除字符串引用以使 React 更简单易懂
// Before class MyComponent extends React.Component { componentDidMount() { this.refs.input.focus(); } render() { return <input ref='input' />; } }
如果仍在使用类组件中的字符串引用,则需要迁移到 refs 回调的形式:
// After class MyComponent extends React.Component { componentDidMount() { this.input.focus(); } render() { return <input ref={input => this.input = input} />; } }
模块模式工厂在2019.8(v16.9.0)被弃用。
// Before function FactoryComponent() { return { render() { return <div />; } } }
这种用法其实很少使用,支持它会使 React 比必要的更大和更慢。在 React 19 中,将删除对模块模式工厂的支持,需要迁移到常规函数:
// After function FactoryComponent() { return <div />; }
React.createFactory
createFactory 在2020.2(v16.13.0)已被弃用。
// Before import { createFactory } from 'react'; const button = createFactory('button');
在 JSX 得到广泛支持之前使用 createFactory 很常见,但是现在已经可以用 JSX 替换。在 React 19 中,将删除 createFactory,需要迁移到 JSX
// After const button = <button />;
react-test-renderer/shallow
在 React 18 中,更新了react-test-renderer/shallow并重新导出react-shallow-renderer。在 React 19 中,将删除react-test-render/shallow,而直接安装该软件包:
react-shallow-renderer
react-test-render/shallow
npm install react-shallow-renderer --save-dev
- import ShallowRenderer from 'react-test-renderer/shallow'; + import ShallowRenderer from 'react-shallow-renderer';
react-dom/test-utils
ReactDOM.render
ReactDOM.render在2022 年 3 月(v18.0.0)已被弃用。
// Before import {render} from 'react-dom'; render(<App />, document.getElementById('root'));
在 React 19 中,将删除 ReactDOM.render,需要迁移到使用ReactDOM.createRoot:
ReactDOM.createRoot
// After import {createRoot} from 'react-dom/client'; const root = createRoot(document.getElementById('root')); root.render(<App />);
ReactDOM.hydrate
ReactDOM.hydrate在2022 年 3 月(v18.0.0)已被弃用。在 React 19 中,将删除 ReactDOM.hydrate,需要迁移到使用ReactDOM.hydrateRoot
ReactDOM.hydrateRoot
// Before import {hydrate} from 'react-dom'; hydrate(<App />, document.getElementById('root')); // After import {hydrateRoot} from 'react-dom/client'; hydrateRoot(document.getElementById('root'), <App />);
unmountComponentAtNode
ReactDOM.unmountComponentAtNode在2022.3(v18.0.0)已被弃用。在 React 19 中需要迁移到使用hydrateRoot和createRoot对应的root.unmount()
ReactDOM.unmountComponentAtNode
root.unmount()
// Before unmountComponentAtNode(document.getElementById('root')); // After root.unmount();
ReactDOM.findDOMNode
ReactDOM.findDOMNode 在2018 年 10 月(v16.6.0)已被弃用
// Before import {findDOMNode} from 'react-dom'; function AutoselectingInput() { useEffect(() => { const input = findDOMNode(this); input.select() }, []); return <input defaultValue="Hello" />; }
可以使用 DOM 引用替换 ReactDOM.findDOMNode
// After function AutoselectingInput() { const ref = useRef(null); useEffect(() => { ref.current.select(); }, []); return <input ref={ref} defaultValue="Hello" /> }
element.ref
从 React 19 开始,现在可以将ref作为函数组件的 prop 访问
ref
如果直接访问 element.ref会出现警告
function MyInput({placeholder, ref}) { return <input placeholder={placeholder} ref={ref} /> } //... <MyInput ref={ref} />
新的函数组件将不再需要forwardRef,在未来的版本中,React 将弃用并删除forwardRef
forwardRef
但是传递给类的 refs 不会作为 props 传递,因为refs引用的是组件实例
refs
react-test-renderer
弃用react-test-renderer。react-test-renderer实现了自己的渲染器环境与用户使用的环境不匹配并依赖于 React 内部的实现细节
在 React 19 中,react-test-renderer会打印了一个弃用警告,并切换到并发渲染。建议将测试迁移到@testing-library/react或@testing-library/react-native以获得更良好支持的测试体验
@testing-library/react
@testing-library/react-native
StrictMode
React 19 包括了对 Strict Mode 的几个修复和改进。在开发中,当在 Strict Mode 下进行双重渲染时,useMemo和useCallback将重用第一次渲染时的结果进行第二次渲染。已经兼容Strict Mode的组件也不会发生差异。与所有Strict Mode行为一样,这些功能为的是在开发过程中主动暴露组件中的错误,以便在它们被发布到生产环境之前修复。例如在开发过程中,Strict Mode将在初始挂载时双重调用ref回调函数,以模拟当挂载的组件被 Suspense 回退替换时的情况
useMemo
useCallback
Strict Mode
UMD 曾经被广泛使用作为一种无需构建步骤即可加载 React 的便捷方式。现在有现代化的替代方案可以将模块作为脚本加载到 HTML 文档中。从 React 19 开始,React 将不再生成 UMD 构建,以减少其测试和发布过程的复杂性。
为了使用脚本标签加载 React 19,可以使用基于 ESM 的 CDN,例如esm.sh
esm.sh
<script type="module"> import React from "https://esm.sh/react@19/?dev" import ReactDOMClient from "https://esm.sh/react-dom@19/client?dev" ... </script>
此版本包含对 React 内部的更改,可能会影响那些忽略 React 官方警告不要使用像SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED这样的内部机制的库。这些更改是为了实现 React 19 中的一些优化,但不会破坏遵循官方指南使用的库。
SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
根据版本策略,这些更新不被列为重大更改,并且不包括有关如何升级它们的文档。建议删除依赖于内部机制的任何代码。
为了反映使用内部机制的影响,已将SECRET_INTERNALS后缀重命名为:
SECRET_INTERNALS
_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
将来将使用更多方式阻止从 React 访问内部,以防止使用并确保用户不会被阻止升级
根据 React 19 中删除的相关 API 清理了相关 TypeScript 类型。同时提供了一个types-react-codemod工具可以帮助迁移已有的类型
types-react-codemod
npx types-react-codemod@latest preset-19 ./path-to-app
由于引入了ref清理函数,从ref回调返回任何其他内容现在将被 TypeScript 报错。修复方法通常是停止使用隐式返回:
- <div ref={current => (instance = current)} /> + <div ref={current => {instance = current}} />
原始代码返回HTMLDivElement的实例,TypeScript 无法确定是否清理函数。
HTMLDivElement
useRef
通过更改类型使得 useRef 现在需要接收一个参数。这显著简化了它的类型签名。现在它的行为更像 createContext
createContext
// @ts-expect-error: Expected 1 argument but saw none useRef(); // Passes useRef(undefined); // @ts-expect-error: Expected 1 argument but saw none createContext(); // Passes createContext(undefined);
现在也意味着所有的引用都是可变的。不再会遇到以下的问题,传递 number类型但是使用 null 初始化
number
null
// before const ref = useRef<number>(null); // Cannot assign to 'current' because it is a read-only property ref.current = 1;
MutableRef现已弃用,建议使用单个RefObject类型,该类型将始终由useRef返回:
MutableRef
RefObject
interface RefObject<T> { current: T } declare function useRef<T>: RefObject<T>
useRef 仍然有一个方便的重载 useRef(null),它自动返回 RefObject<T | null>。为了简化由于 useRef 所需参数的迁移,添加了一个方便的重载 useRef(undefined),它自动返回 RefObject<T | undefined>。
ReactElement
如果元素被标记为ReactElement,则ReactElement的props现在默认为unknown而不是any。如果向ReactElement传递类型参数则不会受到影响
props
unknown
any
type Example2 = ReactElement<{ id: string }>["props"]; // ^? { id: string }
但是如果依赖默认设置,则需要处理unknown:
type Example = ReactElement["props"]; // ^? Before, was 'any', now 'unknown'
类型中删除全局JSX命名空间转而使用React.JSX。防止全局类型的污染和不同 UI 库之间利用 JSX 产生冲突
JSX
React.JSX
现在,需要在declare module中的JSX命名空间的模块进行修改
declare module
// global.d.ts + declare module "react" { namespace JSX { interface IntrinsicElements { "my-element": { myElementProps: string; }; } } + }
准确的模块说明符取决于在tsconfig.json的compilerOptions中指定的 JSX 运行时:
tsconfig.json
compilerOptions
"jsx": "react-jsx"
react/jsx-runtime
"jsx": "react-jsxdev"
react/jsx-dev-runtime
"jsx": "react"
"jsx": "preserve"
react
useReducer
useReducer类型推断得到了改善。然而这需要一个破坏性的变化,其中useReducer不再接受完整的reducer类型作为类型参数,而是需要接收State和Action的类型
reducer
State
Action
新的最佳实践是不要向 useReducer 传递类型参数。
- useReducer<React.Reducer<State, Action>>(reducer) + useReducer(reducer)
这可能在边缘情况下无法正常工作,例如可以通过在元组中传递Action来显式输入状态和操作:
- useReducer<React.Reducer<State, Action>>(reducer) + useReducer<State, [Action]>(reducer)
如果内联定义 reducer,建议注释函数参数:
- useReducer<React.Reducer<State, Action>>((state, action) => state) + useReducer((state: State, action: Action) => state)
这也是如果将 reducer 移动到useReducer调用之外需要做的
const reducer = (state: State, action: Action) => state;
React 19 Beta Upgrade Guide
React 19 Beta
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
React 已于近日发布了
v19
的 beta 版本,同时为了帮助后续的v19
升级,也同时发布了v18.3.0
的正式版, 与v18.2
版本完全相同,但添加了弃用 API 的警告和其他为 React 19 所需的更改安装
使用新版 JSX Transform
为了改善打包体积和可以在 JSX 文件中无需手动引入
React
,在 2020 年 React 引入了新的 JSX Transform。如果在 React 19 中没有使用这个新的 JSX Transform 会有一个报错提示如果已经使用了新版 JSX Transform 则可以忽略此步骤
安装最新版本的 React 和 ReactDom
如果使用 TypeScript,则还需要更新相关类型包。等到 React 19 发布 release 版本后可以就像往常一样从
@types/react
和@types/react-dom
安装类型包。在当前 beta 版本中需要在package.json
为类型包配置overrides
锁定版本以确保不同包中的类型是可用的Breaking changes
render 过程中的错误不再二次抛出
在之前的 React 版本中,渲染过程中抛出的错误会被捕获并重新抛出。在 DEV 模式下,我们还会记录到 console.error,导致出现重复的错误日志。
在 React 19 中,改进了错误处理方式,通过不重新抛出来减少重复信息:
window.reportError
console.error
这个改变不应该影响大多数应用,但如果生产错误报告依赖于错误被重新抛出,则可能需要更新错误处理。为了支持这一点,React 19 添加了新的
createRoot
和hydrateRoot
用于自定义错误处理:废弃 React API 移除
移除
propTypes
和函数组件的defaultProps
propTypes
是用于运行时校验组件 props 的属性,在Reactv15.5.0
已经被标记为废弃,在v19
这个正式删除另外函数组件的
defaultProps
也已经移除(使用 ES6 默认参数替代),由于 class 组件没有相应的 ES6 语法替代因此仍会保留移除使用
contextTypes
和getChildContext
的 Legacy ContextLegacy Context 在2018.10(v16.6.0)已被弃用
Legacy Context 仅适用于使用
contextTypes
和getChildContext
API 的类组件,并由于易于忽略的微妙错误而被contextType
替换。在 React 19 中,将删除 Legacy Context 以使 React 更小更快。仍在类组件中使用 Legacy Context,则需要迁移到新的contextType
API:移除字符串 refs
字符串 refs 在2018.3(v16.3.0)被弃用
在被替换为 ref 回调方式之前类组件支持字符串 refs,但存在多个缺点。在 React 19 中,将删除字符串引用以使 React 更简单易懂
如果仍在使用类组件中的字符串引用,则需要迁移到 refs 回调的形式:
移除模块模式工厂
模块模式工厂在2019.8(v16.9.0)被弃用。
这种用法其实很少使用,支持它会使 React 比必要的更大和更慢。在 React 19 中,将删除对模块模式工厂的支持,需要迁移到常规函数:
移除
React.createFactory
createFactory 在2020.2(v16.13.0)已被弃用。
在 JSX 得到广泛支持之前使用 createFactory 很常见,但是现在已经可以用 JSX 替换。在 React 19 中,将删除 createFactory,需要迁移到 JSX
移除
react-test-renderer/shallow
在 React 18 中,更新了
react-test-renderer/shallow
并重新导出react-shallow-renderer
。在 React 19 中,将删除react-test-render/shallow
,而直接安装该软件包:废弃 ReactDOM API 移除
移除
react-dom/test-utils
移除
ReactDOM.render
ReactDOM.render
在2022 年 3 月(v18.0.0)已被弃用。在 React 19 中,将删除 ReactDOM.render,需要迁移到使用
ReactDOM.createRoot
:移除
ReactDOM.hydrate
ReactDOM.hydrate
在2022 年 3 月(v18.0.0)已被弃用。在 React 19 中,将删除 ReactDOM.hydrate,需要迁移到使用ReactDOM.hydrateRoot
移除
unmountComponentAtNode
ReactDOM.unmountComponentAtNode
在2022.3(v18.0.0)已被弃用。在 React 19 中需要迁移到使用hydrateRoot
和createRoot
对应的root.unmount()
移除
ReactDOM.findDOMNode
ReactDOM.findDOMNode 在2018 年 10 月(v16.6.0)已被弃用
可以使用 DOM 引用替换
ReactDOM.findDOMNode
新增废弃
废弃
element.ref
属性从 React 19 开始,现在可以将
ref
作为函数组件的 prop 访问如果直接访问
element.ref
会出现警告新的函数组件将不再需要
forwardRef
,在未来的版本中,React 将弃用并删除forwardRef
但是传递给类的
refs
不会作为 props 传递,因为refs
引用的是组件实例废弃
react-test-renderer
弃用
react-test-renderer
。react-test-renderer
实现了自己的渲染器环境与用户使用的环境不匹配并依赖于 React 内部的实现细节在 React 19 中,
react-test-renderer
会打印了一个弃用警告,并切换到并发渲染。建议将测试迁移到@testing-library/react
或@testing-library/react-native
以获得更良好支持的测试体验一些值得一提的变动
StrictMode
变化React 19 包括了对 Strict Mode 的几个修复和改进。在开发中,当在 Strict Mode 下进行双重渲染时,
useMemo
和useCallback
将重用第一次渲染时的结果进行第二次渲染。已经兼容Strict Mode
的组件也不会发生差异。与所有Strict Mode
行为一样,这些功能为的是在开发过程中主动暴露组件中的错误,以便在它们被发布到生产环境之前修复。例如在开发过程中,Strict Mode
将在初始挂载时双重调用ref
回调函数,以模拟当挂载的组件被 Suspense 回退替换时的情况移除 UMD 产物
UMD 曾经被广泛使用作为一种无需构建步骤即可加载 React 的便捷方式。现在有现代化的替代方案可以将模块作为脚本加载到 HTML 文档中。从 React 19 开始,React 将不再生成 UMD 构建,以减少其测试和发布过程的复杂性。
为了使用脚本标签加载 React 19,可以使用基于 ESM 的 CDN,例如
esm.sh
依赖于 React 内部的库可能会影响升级
此版本包含对 React 内部的更改,可能会影响那些忽略 React 官方警告不要使用像
SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
这样的内部机制的库。这些更改是为了实现 React 19 中的一些优化,但不会破坏遵循官方指南使用的库。根据版本策略,这些更新不被列为重大更改,并且不包括有关如何升级它们的文档。建议删除依赖于内部机制的任何代码。
为了反映使用内部机制的影响,已将
SECRET_INTERNALS
后缀重命名为:_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
将来将使用更多方式阻止从 React 访问内部,以防止使用并确保用户不会被阻止升级
TypeScript 变化
移除废弃的 TypeScript 类型
根据 React 19 中删除的相关 API 清理了相关 TypeScript 类型。同时提供了一个
types-react-codemod
工具可以帮助迁移已有的类型ref
返回内容必须是清理函数由于引入了
ref
清理函数,从ref
回调返回任何其他内容现在将被 TypeScript 报错。修复方法通常是停止使用隐式返回:原始代码返回
HTMLDivElement
的实例,TypeScript 无法确定是否清理函数。useRef
需要传递参数通过更改类型使得
useRef
现在需要接收一个参数。这显著简化了它的类型签名。现在它的行为更像createContext
现在也意味着所有的引用都是可变的。不再会遇到以下的问题,传递
number
类型但是使用null
初始化MutableRef
现已弃用,建议使用单个RefObject
类型,该类型将始终由useRef
返回:useRef 仍然有一个方便的重载 useRef(null),它自动返回 RefObject<T | null>。为了简化由于 useRef 所需参数的迁移,添加了一个方便的重载 useRef(undefined),它自动返回 RefObject<T | undefined>。
ReactElement
类型变化如果元素被标记为
ReactElement
,则ReactElement
的props
现在默认为unknown
而不是any
。如果向ReactElement
传递类型参数则不会受到影响但是如果依赖默认设置,则需要处理
unknown
:TypeScript 中的 JSX namespace 变化
类型中删除全局
JSX
命名空间转而使用React.JSX
。防止全局类型的污染和不同 UI 库之间利用 JSX 产生冲突现在,需要在
declare module
中的JSX
命名空间的模块进行修改准确的模块说明符取决于在
tsconfig.json
的compilerOptions
中指定的 JSX 运行时:"jsx": "react-jsx"
,将是react/jsx-runtime
。"jsx": "react-jsxdev"
,将是react/jsx-dev-runtime
。"jsx": "react"
和"jsx": "preserve"
,它将是react
。更好的
useReducer
类型useReducer
类型推断得到了改善。然而这需要一个破坏性的变化,其中useReducer
不再接受完整的reducer
类型作为类型参数,而是需要接收State
和Action
的类型新的最佳实践是不要向 useReducer 传递类型参数。
这可能在边缘情况下无法正常工作,例如可以通过在元组中传递
Action
来显式输入状态和操作:如果内联定义 reducer,建议注释函数参数:
这也是如果将 reducer 移动到
useReducer
调用之外需要做的参考
React 19 Beta Upgrade Guide
React 19 Beta
The text was updated successfully, but these errors were encountered: