为React 19做准备:WordPress 6.6用户指南

2024年 7月 19日 50.5k 0

preparing-for-react-19-a-guide-for-wordpress-6.6-users-1024x512-1

作为 WordPress 开发人员,我们经常将自定义的 React 组件集成到我们的主题和插件中,以创建动态和响应式的用户界面。

随着 React 19 的即将发布,为可能影响我们现有代码库的更改和弃用做好准备至关重要。将于 7 月 16 日发布的 WordPress 6.6 包含 React 18.3。该版本与 18.2 几乎完全相同,但增加了对已废弃功能的警告,以帮助您为 React 19 做好准备。

解决这些弃用问题对于确保与 React 19 的兼容性至关重要,忽略它们可能会在 React 19 发布并包含在 WordPress 中时,导致您的自定义区块、插件或主题出现错误或问题。

本文概述了每种弃用情况,提供了代码示例,并指导您替换弃用的功能,以保持功能的流畅性。

注:为了帮助进行升级,React 团队与 Codemod 团队合作发布了一些 codemods,它们会自动将您的代码更新为 React 19 中的许多新 API 和模式。

所有的 codemod 都可以在 GitHub 上的 react-codemod repo 中找到。此外,我们还将附上每个弃用代码的 codemod 命令(如果可用),以帮助您自动更新代码。

React 中已删除的弃用功能

为了精简 React 库并鼓励最佳实践,我们删除了一些已废弃的 API 和功能。本节将介绍主要更改以及如何相应地更新代码。

1. 移除函数组件的 defaultProps

React 19 将移除函数组件的 defaultProps,转而使用 ES6 默认参数。根据 WordPress 团队的说法,这种弃用最常用于插件和主题中。

作为 WordPress 开发人员,您可能会使用 defaultProps 为函数组件中的道具提供默认值,以确保即使没有传递某些道具,组件也能正常运行。

以下是使用 defaultProps 后的当前代码:

function CustomButton({ label, color }) {
return <button style={{ backgroundColor: color }}>{ label }</button>;
}
CustomButton.defaultProps = {
label: 'Click me',
color: 'blue',
};

在本示例中,CustomButton 组件的默认 label 和 color 值由 defaultProps 提供。在 React 19 中,这将引发一个警告错误,提醒您使用 ES6 默认参数。

以下是使用 ES6 默认参数的更新代码:

function CustomButton({ label = 'Click me', color = 'blue' }) {
return <button style={{ backgroundColor: color }}>{ label }</button>;
}

使用 ES6 默认参数,默认值现在直接出现在函数签名中,使代码更易于阅读和维护。

2. 移除函数组件的 propTypes

propTypes 已在 React 15.5.0 中被弃用,并将在 v19 版本的 React 包中完全移除。如果您正在使用 propTypes,建议迁移到 TypeScript 或其他类型检查解决方案。

您可能一直在使用 propTypes 来验证传递给函数组件的道具,以确保它们接收到正确的类型和值。例如:

import PropTypes from 'prop-types';
function CustomButton({ label, color }) {
return <button style={{ backgroundColor: color }}>{ label }</button>;
}
CustomButton.defaultProps = {
label: 'Click me',
color: 'blue',
};
CustomButton.propTypes = {
label: PropTypes.string,
color: PropTypes.string,
};

如今,您可以开始使用 TypeScript 进行这些类型检查:

type CustomButtonProps = {
label?: string;
color?: string;
};
const CustomButton = ({ label = 'Click me', color = 'blue' }: CustomButtonProps) => {
return <button style={{ backgroundColor: color }}>{ label }</button>;
};

注:为了帮助您从使用 propTypes 切换到 TypeScript,您可以使用以下 codemod 命令:

npx codemod@latest react/prop-types-typescript

3. 移除传统上下文(contextTypes 和 getChildContext)

鉴于 WordPress 中许多插件和代码库的长期存在,您可能仍在您的类组件中使用传统的 contextTypesgetChildContext API。这些应用程序接口用于将数据从父组件传递到其子组件,而无需在每个层级明确传递道具。

不过,值得注意的是,传统上下文已在 React 16.6.0 中被弃用,并将在 React v19 中移除。这一改动的目的是让 React 稍微更小更快,因为传统 Context API 有一些细微的 bug,经常容易被忽视。

传统方法已被新的 contextType API 所取代。

下面是一个示例,说明您如何在 WordPress 插件中使用已废弃的 Context API,将全局设置(如网站标题)从父组件传递到子组件,而无需进行道具钻取:

import PropTypes from 'prop-types';
class SettingsProvider extends React.Component {
static childContextTypes = {
siteTitle: PropTypes.string.isRequired,
};
getChildContext() {
return { siteTitle: 'My WordPress Site' };
}
render() {
return <SettingsConsumer />;
}
}
class SettingsConsumer extends React.Component {
static contextTypes = {
siteTitle: PropTypes.string.isRequired,
};
render() {
return <div>Site Title: {this.context.siteTitle}</div>;
}
}

相比之下,现代方法使用 createContext 方法。在准备 React 19 时,您应该采用这种方法:

import React from 'react';
const SettingsContext = React.createContext();
class SettingsProvider extends React.Component {
render() {
return (
<SettingsContext value={{ siteTitle: 'My WordPress Site' }}>
<SettingsConsumer />
</SettingsContext>
);
}
}
class SettingsConsumer extends React.Component {
static contextType = SettingsContext;
render() {
const { siteTitle } = this.context;
return <div>Site Title: { siteTitle }</div>;
}
}

4. 移除字符串引用

使用字符串引用曾是在 React 组件中访问 DOM 元素的常用方法。不过,自 React 16.3.0 以来,这种方法一直被视为传统方法,并将在 v19 中移除。

字符串引用虽然简单明了,但也存在一些问题,例如潜在的命名冲突和缺乏灵活性。

请看一个在 WordPress 自定义块中使用字符串引用的例子。想象一下,您有一个包含输入框的 Gutenberg 自定义区块,您希望在将该区块添加到编辑器时自动聚焦输入框。下面是您如何使用字符串引用来实现这一目的:

class CustomBlock extends React.Component {
componentDidMount() {
this.refs.input.focus();
}
render() {
return <input ref="input" placeholder="Enter text..." />;
}
}

要为 React 19 做好准备,您必须使用回调 refReact.createRef API 替换字符串 ref。下面是使用回调 ref 的相同示例:

class CustomBlock extends React.Component {
componentDidMount() {
this.input.focus();
}
render() {
return <input ref={(input) => (this.input = input)} placeholder="Enter text..." />;
}
}

注:为了帮助您从使用字符串 ref 切换到回调 ref,您可以使用以下 codemod 命令:

npx codemod@latest react/19/replace-string-ref

5. 移除模块模式工厂

React 19 将移除的另一个废弃功能是模块模式工厂。这种模式很少被使用,而且会导致 React 略微变大和变慢。

模块模式工厂允许开发人员不那么传统地创建组件。下面是一个您可能正在使用它的示例:

function SettingsPanelFactory() {
return {
render() {
return (
<div className="settings-panel">
<h2>Settings</h2>
{/* other settings UI components */}
</div>
);
}
};
}

在此模式中,SettingsPanelFactory 使用 render 方法返回对象,而不是直接返回 JSX。

为了符合 React 19 的要求,您必须将模块模式工厂迁移到直接返回 JSX 的常规函数。以下是更新后的示例:

function SettingsPanel() {
return (
<div className="settings-panel">
<h2>Settings</h2>
{/* other settings UI components */}
</div>
);
}

6. 移除 createFactory API

React 19 将移除 React.createFactory。在JSX得到广泛支持之前,这种方法比较常用。它允许开发人员在不使用 JSX 语法的情况下创建 React 元素。

不过,随着 JSX 的普及,createFactory 已经过时,可以用更简单、更易读的 JSX 代码来替代。

下面是一个使用 createFactory 创建 button 元素的示例。这可能是自定义 WordPress 插件的一部分,该插件可根据用户输入动态生成 button 元素:

import { createFactory } from 'react';
const button = createFactory('button');
function CustomButton() {
return button({ className: 'custom-button', type: 'button' }, 'Click Me');
}

要为 React 19 更新此代码,请将 createFactory 替换为 JSX。这一改动使代码更现代、更易读、更易维护:

function CustomButton() {
return <button className="custom-button" type="button">Click Me</button>;
}

7. 移除 react-test-renderer/shallow

React 19 删除了 react-test-renderer/shallow,以简化测试实用程序并鼓励最佳实践。在 React 18 中,react-test-renderer/shallow 已更新为重新导出 react-shallow-renderer。

以前,您可能会使用 react-test-renderer/shallow 为 React 组件创建浅层呈现测试:

import ShallowRenderer from 'react-test-renderer/shallow';
test('MyComponent shallow render', () => {
const renderer = new ShallowRenderer();
renderer.render(<MyComponent />);
const result = renderer.getRenderOutput();
expect(result.type).toBe('div');
});

要符合 React 19 的要求,需要安装 react-shallow-renderer:

npm install react-shallow-renderer --save-dev

并更新您的导入:

import ShallowRenderer from 'react-shallow-renderer';
test('MyComponent shallow render', () => {
const renderer = new ShallowRenderer();
renderer.render(<MyComponent />);
const result = renderer.getRenderOutput();
expect(result.type).toBe('div');
});

React 团队建议迁移到 React 测试库,该库通过关注用户如何与组件交互来提供更强大的测试实践。

为此,请将 @testing-library/react 库作为开发依赖安装:

npm install @testing-library/react --save-dev

接下来,您可以使用这种现代方法测试同一个组件:

import { render, screen } from '@testing-library/react';
import MyBlock from './MyBlock';
test('MyBlock renders correctly', () => {
render(<MyBlock />);
const element = screen.getByText('MyBlock content');
expect(element).toBeInTheDocument();
});

删除 React DOM 中的弃用方法

React DOM 在 React 19 中也发生了变化,删除了某些已废弃的方法。本节将概述这些更改,并指导您更新与 DOM 相关的代码。

1. 删除 react-dom/test-utils API

react-dom/test-utils API 也将在 React 19 中移除。这将影响我们为 React 组件编写测试的方式。具体来说,act 工具已从 react-dom/test-utils 移至 react 包。

此外,react-dom/test-utils 中的大多数其他实用工具也已移除。下面介绍如何调整测试以适应这些变化。

act 实用程序对于确保与测试相关的所有更新都已处理并应用到 DOM 至关重要。在 React 19 中,您应该直接从 react 中导入 act,而不是 react-dom/test-utils

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

注:为了帮助你从使用 react-dom/test-utils 切换到新的导入,你可以使用下面的 codemod 命令:

npx codemod@latest react/19/replace-act-import

React 团队还建议将您的测试迁移到 React 测试库,以获得现代化且支持良好的测试体验。以下是一些常见用例以及如何更新它们。

renderIntoDocument 实用程序将被移除。您可以使用 @testing-library/react 中的 render 来替换它。

// Before
import { renderIntoDocument } from 'react-dom/test-utils';
renderIntoDocument(<Component />);
// Now
import { render } from '@testing-library/react';
render(<Component />);

同样,用于模拟事件的 Simulate 工具也将被移除。取而代之的是使用 @testing-library/react 中的 fireEvent,它会在元素上派发实际事件。

// Before
import { Simulate } from 'react-dom/test-utils';
const element = document.querySelector('button');
Simulate.click(element);
// Now
import { fireEvent } from '@testing-library/react';
const element = document.querySelector('button');
fireEvent.click(element);

请注意,fireEvent 派发的是真实事件,这意味着它与元素的交互比模拟创建的合成事件更自然。要正确理解 React 测试库,请阅读其文档。

2. 删除 findDOMNode API

React 19 的另一个重大变化是移除了 ReactDOM .findDOMNode,该函数在 React 16.6.0 中已被弃用。

该函数用于访问 React 组件的底层 DOM 节点,但它有几个缺点,例如执行速度慢、易受重构影响和破坏抽象层。

相反,您应该使用 DOM refs,它提供了一种更可靠、更高效的方式来与 React 组件中的 DOM 元素进行交互。

下面是使用 findDOMNode 在组件挂载时选择输入字段中文本的示例:

import { findDOMNode } from 'react-dom';
function AutoselectingInput() {
useEffect(() => {
const input = findDOMNode(this);
input.select()
}, []);
render() {
return <input defaultValue="Hello" />;
}
}

要为 React 19 更新此代码,请将 findDOMNode 替换为 ref。这一改动使代码更加健壮,并与现代 React 实践保持一致:

import React, { useEffect, useRef } from 'react';
function AutoselectingInput() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.select();
}, []);
return <input ref={inputRef} defaultValue="Hello" />;
}

3. 移除渲染 API

React 19 将移除 ReactDOM. render。该方法已在 React 18.0.0 中被弃用,取而代之的是 react-dom/client 中的 createRoot API,它为初始化和渲染 React 应用程序提供了一种更高效、更现代的方式。这一变化是 React 为简化和优化库而持续努力的一部分。

在典型的 WordPress 设置中,您可能会有一个自定义块或插件,在 DOM 准备就绪时初始化 React 应用程序。以前,您会使用 ReactDOM.render

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

在 React 19 中,您应该使用 createRoot 来初始化和呈现您的 React 应用程序:

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

注:为了帮助您从使用 ReactDOM.render 切换到 react-dom/client 的 createRoot API,您可以使用以下 codemod 命令:

npx codemod@latest react/19/replace-reactdom-render

4. 删除 unmountComponentAtNode API

React 19 还移除了 ReactDOM.unmountComponentAtNode 方法,该方法在 React 18.0.0 中已被弃用。

在 React 19 中,您应该迁移到使用 root.unmount() 方法,该方法更符合用于创建和水化根的更新 API。

// Before
unmountComponentAtNode(document.getElementById('root'));
// Now
root.unmount();

注:要从使用 unmountComponentAtNode 切换到 root.unmount,可以使用以下 codemod 命令:

npx codemod@latest react/19/replace-reactdom-render

5. 移除 hydrate API

ReactDOM.hydrate 在 React18 中被弃用,并将在 React 19 中完全移除。

React DOM 客户端 API 的新方法 hydrateRoot 将取代 ReactDOM.hydrate,为服务器渲染的 React 应用程序提供更高效、更现代的水合方式。

在 WordPress 环境中,您可能会使用服务器端渲染(SSR)来交付初始 HTML 内容,以加快页面加载速度。要将这些内容水合到交互式 React 应用程序中,您以前需要使用 ReactDOM.hydrate

import { hydrate } from 'react-dom';
import App from './App.js';
hydrate(
<App />,
document.getElementById('root')
);

使用 React 19 时,应使用react-dom/client中的hydrateRoot进行 hydration:

import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(
document.getElementById('root'),
<App />
);

注:To help you switch from ReactDOM.hydrate to ReactDOMClient.hydrateRoot, you can use the following codemod command:

npx codemod@latest react/19/replace-reactdom-render

删除已废弃的 TypeScript 类型

WordPress 开发人员经常使用 TypeScript 为 React 组件添加类型安全性并提高代码质量。在 React 19 中,一些已被弃用的 TypeScript 类型已被移除或迁移到更相关的包中。

了解这些变化对于确保您的代码库保持稳健并与最新的 React 版本兼容至关重要。

为了协助过渡,React 团队提供了一个名为 types-react-codemod 的工具,它可以自动更新您的代码库以处理这些变更。

要使用该工具,请运行下面的 codemod 命令,其中包含几个用于更新已废弃类型的转换。

npx types-react-codemod@latest preset-19 ./path-to-app

该工具还提供互动模式,您可以选择要应用的特定变换:

? Pick transforms to apply (Press  to select,  to toggle all,  to invert selection, and  to proceed)
❯◯ context-any
◉ deprecated-react-type
◉ deprecated-sfc-element
◉ deprecated-sfc
◉ deprecated-stateless-component
◯ implicit-children
◯ useCallback-implicit-any

让我们举例说明一些关键的变化。

1. 需要 ref 清理

在 React 19 中,ref 清理函数通过在 ref 回调中强制执行显式返回来提高类型安全性。隐式返回会导致 TypeScript 误解返回值。

// Before
(instance = current)} />
// Now
{ instance = current }} />

2. useRef 需要一个参数

以前,useRef 可以在没有参数的情况下调用,从而导致潜在的类型问题。在 React 19 中,useRef 需要一个参数,以确保 ref 始终是可变的。

// Before — @ts-expect-error: Expected 1 argument but saw none
useRef();
// Now — correct usage with an argument
useRef(undefined);

3. 对 ReactElement TypeScript 类型的更改

ReactElement props 的默认类型已从 any 变为 unknown,通过要求显式处理未知类型,提高了类型安全性。

// Previously, this was 'any'
type Example = ReactElement["props"];
// Now, this is 'unknown'
type Example = ReactElement["props"];

如果您的代码依赖于any 类型,则必须更新代码以显式处理 unknown 类型或将其转换为 any 类型。

小结

作为 WordPress 开发人员,了解 React 的最新进展至关重要。本指南将确保您了解 React 即将发生的各种变化,以便将它们应用到您的 WordPress 项目中。

最后一条信息: React 19 将要求使用新的 JSX transform。好消息是,WordPress 6.6 已经配备了它。如果未启用新 transform,您将看到以下警告:

Your app (or one of its dependencies) is using an outdated JSX transform. Update to the modern JSX transform for faster performance: https://react.dev/link/new-jsx-transform

您所要做的就是停止使用 React 导入进行 JSX 转换,因为它们已不再必要。

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
如何删除WordPress中的所有评论
检查WordPress服务器磁盘使用情况的7种简便方法(查找大文件和数据)

发布评论