React 19 公测版升级完全指南:破坏性更改

发布于:2024-04-29 ⋅ 阅读:(22) ⋅ 点赞:(0)

给前端以福利,给编程以复利。大家好,我是大家的林语冰。

React 团队爆料最新主版本升级 React 19 Beta(公测版)已经正式上线 npm,想要提前沉浸式体验最新版本的 React 发烧友可以深度阅读这份 React 官方博客的升级指南。

React 19 中新增的改进需要某些破坏性更改,但预计这些变更不会影响大多数应用程序。

在这篇 React 官方博客中,我们将指导你将库升级到 React 19 beta(公测版)的完整步骤中涉及的破坏性更改。

react.png

免责声明

本文属于是语冰的直男翻译了属于是,略有删改,仅供粉丝参考。英文原味版请传送 。

React 18.3 正式发布

为了辅助你更轻松地升级到 React 19,我们发布了与 React 18.2 等价的 react@18.3 版本,但添加了废弃 API 的相关警告,以及 React 19 所需的其他变更。

粉丝请注意,React 19 公测版是 React 19 主版本的前戏。React 发烧友请先升级到 React 18.3,然后耐心等待 React 19 稳定版,切勿操之过急,否则后果自负。

如果你想辅助我们测试 React 19,请按照这份升级指南中的步骤操作,并报告你遭遇的任何问题。

安装

我们现在需要新型 JSX 转换

我们在 2020 年引入了新型 JSX 转换,改进打包体积,且在不导入 React 的情况下使用 JSX。

在 React 19 中,我们新增了其他改进,比如使用 ref 作为 prop,以及需要新型转换的 JSX 速度优化。 我们预计大多数应用程序不会受到影响,因为转换在大多数环境中已经启动。

安装最新版本的 React 和 React DOM:

npm install react@beta react-dom@beta

如果你使用 TS,你还需要更新类型。一旦 React 19 稳定发布,你就可以照常安装 @types/react@types/react-dom 中的类型。

在公测期间,这些类型在不同的包中可用,这需要在你的 package.json 中强制升级:

{
  "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 早​​期版本中,渲染时抛出的错误会被捕获,且重新抛出。在开发环境中,我们还会打印到 console.error,导致重复的错误日志。

在 React 19 中,我们改进了错误处理方式,禁止重新抛出从而减少重复:

  • 未捕获的错误:Error Boundary 未捕获的错误将报告给 window.reportError
  • 捕获的错误:Error Boundary 捕获的错误将报告给 console.error

此更改不会影响大多数应用程序,但如果你的生产错误报告依赖重新抛出的错误,你可能需要更新错误处理。

为了支持这一点,我们向 createRoothydrateRoot 添加了新方法,来进行自定义错误处理:

const root = createRoot(container, {
  onUncaughtError: (error, errorInfo) => {
    // ... 打印错误报告
  },
  onCaughtError: (error, errorInfo) => {
    // ... 打印错误报告
  }
})

已删除弃用的 React API

已删除:函数的 propTypesdefaultProps

PropTypes 于 2017 年 4 月(React 15.5)已弃用。

在 React 19 中,我们从 React 包中删除了 propType 检查,并且使用它们将被静默忽略。如果你在使用 propTypes,我们建议迁移到 TS 或其他类型检查方案。

我们还从函数组件中删除了 defaultProps,使用 ES6 的默认参数代替。由于没有 ES6 替代方案,类式组件将继续支持 defaultProps

// 切换前:
import PropTypes from 'prop-types'

function Heading({ text }) {
  return <h1>{text}</h1>
}
Heading.propTypes = {
  text: PropTypes.string
}
Heading.defaultProps = {
  text: 'Hello, world!'
}

// 切换后:
interface Props {
  text?: string
}
function Heading({ text = 'Hello, world!' }: Props) {
  return <h1>{text}</h1>
}

已删除:使用 contextTypesgetChildContext 的过时 Context

过时的 Context 于 2018 年 10 月(React 16.6)已弃用。

过时的 Context 能且仅能在使用 contextTypesgetChildContext API 的类式组件中可用,且由于存在感低下的细微 bug 而被 contextType 替换。

在 React 19 中,我们删除了过时的 Context,使 React 更加短小精悍。

如果你仍在类式组件中使用过时 Context,则需要迁移到新的 contextType API:

// 切换前:
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>
  }
}

// 切换后:
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>
  }
}

已删除:字符串 ref

字符串 ref 于 2018 年 3 月(React 16.3.0)已弃用。

类式组件支持字符串 ref,之后由于若干缺陷被 ref 回调函数取代。在 React 19 中,我们删除了字符串 ref,使 React 更简单粗暴。

如果你仍在类式组件中使用字符串 ref,则需要迁移到 ref 回调函数:

// 切换前:
class MyComponent extends React.Component {
  componentDidMount() {
    this.refs.input.focus()
  }

  render() {
    return <input ref="input" />
  }
}

// 切换后:
class MyComponent extends React.Component {
  componentDidMount() {
    this.input.focus()
  }

  render() {
    return <input ref={input => (this.input = input)} />
  }
}

粉丝请注意,为了辅助迁移,React 团队将发布一个 react-codemod,自动用 ref 回调函数替换字符串 ref

已删除:模块模式工厂

模块模式工厂于 2019 年 8 月(React 16.9)已弃用。

这种模式很少使用,且支持它会导致 React 更大更慢。在 React 19 中,我们将删除对模块模式工厂的支持,你需要迁移到常规函数:

// 切换前:
function FactoryComponent() {
  return {
    render() {
      return <div />
    }
  }
}

// 切换后:
function FactoryComponent() {
  return <div />
}

已删除:React.createFactory

createFactory 于 2020 年 2 月(React 16.13)已弃用。

在 JSX 得到广泛支持之前,使用 createFactory 司空见惯,但如今寥寥无几,且以用 JSX 代替。

在 React 19 中,我们将删除 createFactory,你需要迁移到 JSX:

// 切换前:
import { createFactory } from 'react'

const button = createFactory('button')

// 切换后:
const button = <button />

已删除:react-test-renderer/shallow

在 React 18 中,我们更新了 react-test-renderer/shallow,来重新导出 react-shallow-renderer

在 React 19 中,我们删除了 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 内部结构,且可能会阻止你未来的升级。我们建议将你的测试迁移到 @testing-library/react@testing-library/react-native

删除了已弃用的 React DOM API

已删除:react-dom/test-utils

我们已将 actreact-dom/test-utils 移至 react 包,你可以从 react 导入 act

- import {act} from 'react-dom/test-utils'
+ import {act} from 'react';

所有其他 test-utils 功能已删除。这些实用程序并不常见,且很容易依赖组件和 React 的低级实现细节。

在 React 19 中,这些函数在调用时会出错,且它们的导出将在未来版本中删除。

已删除:ReactDOM.render

ReactDOM.render 已于 2022 年 3 月(React 18)弃用。

在 React 19 中,我们将删除 ReactDOM.render,你需要迁移到使用 ReactDOM.createRoot

// 切换前:
import { render } from 'react-dom'
render(<App />, document.getElementById('root'))

// 切换后:
import { createRoot } from 'react-dom/client'
const root = createRoot(document.getElementById('root'))
root.render(<App />)

已删除:ReactDOM.hydrate

ReactDOM.hydrate 已于 2022 年 3 月弃用(React 18)。

在 React 19 中,我们删除了 ReactDOM.hydrate,你需要迁移到使用 ReactDOM.hydrateRoot

// 切换前:
import { hydrate } from 'react-dom'
hydrate(<App />, document.getElementById('root'))

// 切换后:
import { hydrateRoot } from 'react-dom/client'
hydrateRoot(document.getElementById('root'), <App />)

已删除:unmountComponentAtNode

ReactDOM.unmountComponentAtNode 已于 2022 年 3 月弃用(React 18)。

在 React 19 中,你需要迁移到使用 root.unmount()

// 切换前:
unmountComponentAtNode(document.getElementById('root'))

// 切换后:
root.unmount()

已删除:ReactDOM.findDOMNode

ReactDOM.findDOMNode 已于 2018 年 10 月(React 16.6)弃用。

我们正在删除 findDOMNode,因为它是一个过时的逃生舱口,执行速度慢,重构脆弱,仅返回第一个子级元素,并且破坏了抽象级别。

你可以将 ReactDOM.findDOMNode 替换为 DOM refs

// 切换前:
import { findDOMNode } from 'react-dom'

function AutoselectingInput() {
  useEffect(() => {
    const input = findDOMNode(this)
    input.select()
  }, [])

  return <input defaultValue="Hello" />
}

// 切换后:
function AutoselectingInput() {
  const ref = useRef(null)
  useEffect(() => {
    ref.current.select()
  }, [])

  return <input ref={ref} defaultValue="Hello" />
}

参考文献

  1. React
  2. Upgrade Guide
  3. React 19 Beta

粉丝互动

本期话题是:如何评价 React 19 Beta 公测版?你可以在本文下方自由言论,文明科普。

欢迎持续关注“前端俱乐部”,给前端以福利,给编程以复利。

坚持阅读的小伙伴可以给自己点赞!谢谢大家的点赞,掰掰~

26-cat.gif


网站公告

今日签到

点亮在社区的每一天
去签到