As WordPress developers, we often integrate custom React components into our themes and plugins to create dynamic and responsive user interfaces.
With the upcoming release of React 19, it’s crucial to prepare for changes and deprecations that could impact our existing codebases. WordPress 6.6, which was recently released, includes React 18.3. This version is nearly identical to 18.2 but adds warnings for deprecated features to help you prepare for React 19.
Addressing these deprecations is essential to ensure compatibility with React 19, and ignoring them can lead to bugs or issues in your custom blocks, plugins, or themes when React 19 is released and included in WordPress.
This article outlines each deprecation, provides code examples, and guides you through replacing deprecated features to maintain smooth functionality.
Removed deprecations in React
Several deprecated APIs and features have been removed to streamline the React library and encourage best practices. This section covers the key changes and how to update your code accordingly.
1. Removal of defaultProps for function components
React 19 will remove defaultProps
for function components in favor of ES6 default parameters. According to the WordPress team, this deprecation is most commonly used in plugins and themes.
As a WordPress developer, you might use defaultProps
to provide default values for props in your function components, ensuring that components behave correctly even if certain props are not passed.
Here is what your current code may look like with defaultProps
:
function CustomButton({ label, color }) {
return ;
}
CustomButton.defaultProps = {
label: 'Click me',
color: 'blue',
};
In this example, a CustomButton
component has default label
and color
values provided by defaultProps
. With React 19, this will throw a warning error, urging you to use ES6 default parameters instead.
Here is the updated code with ES6 default parameters:
function CustomButton({ label="Click me", color="blue" }) {
return ;
}
Using ES6 default parameters, the default values are now directly in the function signature, making the code easier to read and maintain.
2. Removal of propTypes for function components
propTypes
was deprecated in React 15.5.0 and will also be completely removed in the React package in v19. If you’re using propTypes
, it’s recommended that you migrate to TypeScript or another type-checking solution.
You might have been using propTypes
to validate the props passed to your function components to ensure they receive the correct types and values. For example:
import PropTypes from 'prop-types';
function CustomButton({ label, color }) {
return ;
}
CustomButton.defaultProps = {
label: 'Click me',
color: 'blue',
};
CustomButton.propTypes = {
label: PropTypes.string,
color: PropTypes.string,
};
Today, you can start using TypeScript for these type-checkings:
type CustomButtonProps = {
label?: string;
color?: string;
};
const CustomButton = ({ label="Click me", color="blue" }: CustomButtonProps) => {
return ;
};
3. Removal of Legacy Context (contextTypes and getChildContext)
Given the longstanding nature of many plugins and codebases in WordPress, you might still be using the legacy contextTypes
and getChildContext
APIs in your class components. These APIs were used to pass data from a parent component to its descendants without explicitly passing props at each level.
However, it’s important to note that Legacy Context was deprecated in React 16.6.0 and will be removed in React v19. This change is intended to make React slightly smaller and faster, as the Legacy Context API had subtle bugs that were often easy to overlook.
The legacy method has been replaced with the new contextType
API.
Here’s an example of how you may be using the deprecated Context API in a WordPress plugin to pass global settings, such as the site title, from a parent component to a child component without prop drilling:
import PropTypes from 'prop-types';
class SettingsProvider extends React.Component {
static childContextTypes = {
siteTitle: PropTypes.string.isRequired,
};
getChildContext() {
return { siteTitle: 'My WordPress Site' };
}
render() {
return ;
}
}
class SettingsConsumer extends React.Component {
static contextTypes = {
siteTitle: PropTypes.string.isRequired,
};
render() {
return Site Title: {this.context.siteTitle}
;
}
}
In contrast, the modern approach uses the createContext
method. This is the method you should adopt as you prepare for React 19:
import React from 'react';
const SettingsContext = React.createContext();
class SettingsProvider extends React.Component {
render() {
return (
);
}
}
class SettingsConsumer extends React.Component {
static contextType = SettingsContext;
render() {
const { siteTitle } = this.context;
return Site Title: { siteTitle }
;
}
}
4. Removal of string refs
Using string refs was once a common way to access a DOM element in React components. However, they have been considered legacy since React 16.3.0 and will be removed in v19.
While string refs were straightforward, they had several issues, such as potential naming conflicts and a lack of flexibility.
Consider an example of using string refs in a WordPress custom block. Imagine you have a custom Gutenberg block that includes an input field, and you want the input field to be focused automatically when the block is added to the editor. Here’s how you might have done this using string refs:
class CustomBlock extends React.Component {
componentDidMount() {
this.refs.input.focus();
}
render() {
return ;
}
}
To prepare for React 19, you must replace string refs with callback refs
or the React.createRef
API. Here’s the same example using a callback ref
:
class CustomBlock extends React.Component {
componentDidMount() {
this.input.focus();
}
render() {
return (this.input = input)} placeholder="Enter text..." />;
}
}
5. Removal of module pattern factories
Another deprecated feature that will be removed in React 19 is module pattern factories. This pattern was rarely used and caused React to be slightly larger and slower than necessary.
Module pattern factories allowed developers to create components less conventionally. Here’s an example of how you may be using it:
function SettingsPanelFactory() {
return {
render() {
return (
Settings
{/* other settings UI components */}
);
}
};
}
In this pattern, SettingsPanelFactory
returns an object using a render
method rather than returning JSX directly.
To comply with React 19, you must migrate module pattern factories to regular functions that return JSX directly. Here’s the updated example:
function SettingsPanel() {
return (
Settings
{/* other settings UI components */}
);
}
6. Removal of createFactory API
In React 19, React.createFactory
is being removed. This method was more commonly used before JSX became widely supported. It allowed developers to create React elements without using JSX syntax.
However, with the prevalence of JSX, createFactory
has become obsolete and can be replaced with simpler, more readable JSX code.
Here’s an example of using createFactory
to create a button
element. This might be part of a custom WordPress plugin that dynamically generates button
elements based on user input:
import { createFactory } from 'react';
const button = createFactory('button');
function CustomButton() {
return button({ className: 'custom-button', type: 'button' }, 'Click Me');
}
To update this code for React 19, replace createFactory
with JSX. This change makes the code more modern, readable, and maintainable:
function CustomButton() {
return ;
}
7. Removal of react-test-renderer/shallow
React 19 removes react-test-renderer/shallow
to streamline the testing utilities and encourage best practices. In React 18, react-test-renderer/shallow
was updated to re-export react-shallow-renderer
.
Previously, you might have used react-test-renderer/shallow
to create shallow render tests for your React components:
import ShallowRenderer from 'react-test-renderer/shallow';
test('MyComponent shallow render', () => {
const renderer = new ShallowRenderer();
renderer.render( );
const result = renderer.getRenderOutput();
expect(result.type).toBe('div');
});
To comply with React 19, you need to install react-shallow-renderer
:
npm install react-shallow-renderer --save-dev
And update your import:
import ShallowRenderer from 'react-shallow-renderer';
test('MyComponent shallow render', () => {
const renderer = new ShallowRenderer();
renderer.render( );
const result = renderer.getRenderOutput();
expect(result.type).toBe('div');
});
The React team recommends migrating to the React Testing Library, which provides more robust testing practices by focusing on how users interact with your components.
To do this, install the @testing-library/react
library as a dev dependency:
npm install @testing-library/react --save-dev
Next, you can test the same component using this modern approach:
import { render, screen } from '@testing-library/react';
import MyBlock from './MyBlock';
test('MyBlock renders correctly', () => {
render( );
const element = screen.getByText('MyBlock content');
expect(element).toBeInTheDocument();
});
Removed deprecations in React DOM
React DOM has also changed in React 19, with certain deprecated methods removed. This section outlines these changes and guides you through updating your DOM-related code.
1. Removal of react-dom/test-utils API
The react-dom/test-utils
API will also be removed in React 19. This impacts how we write tests for our React components. Specifically, the act
utility has been moved from react-dom/test-utils
to the react
package.
Additionally, most other utilities from react-dom/test-utils
have been removed. Here’s how to adapt your tests to comply with these changes.
The act
utility is essential for ensuring that all updates related to your tests have been processed and applied to the DOM. In React 19, you should import act
directly from react
instead of react-dom/test-utils
.
// Before
import { act } from 'react-dom/test-utils';
// Now
import { act } from 'react';
The React team also recommends migrating your tests to the React Testing Library for a modern and well-supported testing experience. Here are some common use cases and how to update them.
The renderIntoDocument
utility will be removed. You can replace it with render
from @testing-library/react
.
// Before
import { renderIntoDocument } from 'react-dom/test-utils';
renderIntoDocument( );
// Now
import { render } from '@testing-library/react';
render( );
Similarly, the Simulate
utility for simulating events will be removed. Instead, you should use fireEvent
from @testing-library/react
, which dispatches an actual event on the element.
// 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);
Be aware that fireEvent
dispatches a real event, which means it interacts with the element more naturally than the synthetic events created by Simulate
. To properly understand the React testing library, read its documentation.
2. Removal of findDOMNode API
Another significant change coming to React 19 is the removal of ReactDOM.findDOMNode
, which was deprecated in React 16.6.0.
This function was used to access the underlying DOM node of a React component, but it had several drawbacks, such as being slow to execute, fragile to refactoring, and breaking abstraction levels.
Instead, you should use DOM refs, which provide a more reliable and efficient way to interact with DOM elements in your React components.
Here’s an example of using findDOMNode
to select the text in an input field when the component mounts:
import { findDOMNode } from 'react-dom';
function AutoselectingInput() {
useEffect(() => {
const input = findDOMNode(this);
input.select()
}, []);
render() {
return ;
}
}
To update this code for React 19, replace findDOMNode
with a ref
. This change makes the code more robust and aligns it with modern React practices:
import React, { useEffect, useRef } from 'react';
function AutoselectingInput() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.select();
}, []);
return ;
}
3. Removal of render API
With React 19, ReactDOM.render
will be removed. This method was deprecated in React 18.0.0 in favor of createRoot
API from react-dom/client
, which provides a more efficient and modern way to initialize and render React applications. This change is part of React’s ongoing effort to streamline and optimize the library.
In a typical WordPress setup, you might have a custom block or a plugin that initializes a React app when the DOM is ready. Previously, you would use ReactDOM.render
:
import { render } from 'react-dom';
render( , document.getElementById('root'));
With React 19, you should use createRoot
to initialize and render your React application:
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render( );
4. Removal of unmountComponentAtNode API
React 19 also removes the ReactDOM.unmountComponentAtNode
method, which was deprecated in React 18.0.0. This method was used to unmount a React component from the DOM.
In React 19, you should migrate to using the root.unmount()
method, which is more aligned with the updated API for creating and hydrating roots.
// Before
unmountComponentAtNode(document.getElementById('root'));
// Now
root.unmount();
5. Removal of hydrate API
ReactDOM.hydrate was deprecated in React 18 and will be completely removed in React 19.
The new method of the React DOM client API, hydrateRoot
, replaces ReactDOM.hydrate
, providing a more efficient and modern way to hydrate server-rendered React applications.
In a WordPress context, you might use server-side rendering (SSR) to deliver initial HTML content for faster page loads. To hydrate this content into an interactive React application, you would previously use ReactDOM.hydrate
:
import { hydrate } from 'react-dom';
import App from './App.js';
hydrate(
,
document.getElementById('root')
);
With React 19, you should use hydrateRoot
from react-dom/client
for hydration:
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(
document.getElementById('root'),
);
Removed deprecated TypeScript types
WordPress developers often use TypeScript to add type safety and improve code quality in React components. With React 19, several deprecated TypeScript types have been removed or relocated to more relevant packages.
Understanding these changes is crucial for ensuring your codebase remains robust and compatible with the latest React version.
To assist with the transition, the React team has provided a tool called types-react-codemod
, which can automatically update your codebase to handle these changes.
To use it, run the following codemod command, which includes several transforms to update deprecated types.
npx types-react-codemod@latest preset-19 ./path-to-app
The tool also offers an interactive mode where you can pick specific transforms to apply:
? 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
Let’s take a look at some key changes with examples.
1. Ref cleanup required
With React 19, ref
cleanup functions improve type safety by enforcing explicit returns in ref
callbacks. Implicit returns can cause TypeScript to misinterpret the return value.
// Before
(instance = current)} />
// Now
{ instance = current }} />
2. useRef requires an argument
Previously, useRef
could be called without arguments, leading to potential type issues. In React 19, useRef
requires an argument to ensure that refs are always mutable.
// Before — @ts-expect-error: Expected 1 argument but saw none
useRef();
// Now — correct usage with an argument
useRef(undefined);
3. Changes to the ReactElement TypeScript Type
The default type for ReactElement
props has changed from any
to unknown
, improving type safety by requiring explicit handling of unknown types.
// Previously, this was 'any'
type Example = ReactElement["props"];
// Now, this is 'unknown'
type Example = ReactElement["props"];
If your code relied on any
, you must update it to handle unknown
explicitly or cast it to any
.
Summary
As WordPress developers, staying updated with the latest React advancements is crucial. This guide ensures you understand the various changes coming to React so you can apply them to your WordPress projects.
One last piece of information: With React 19, the new JSX transform will be required. The good news is that it already comes with WordPress 6.6. If the new transform isn’t enabled, you’ll see this warning:
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
All you have to do is stop using React imports for JSX transformations, as they are no longer necessary.
Did we miss anything? Please share with us in the comments section!