React is an open-source, JavaScript front-end library for building user interfaces. It works fast, is easy to learn, and is efficient, especially in creating scalable and reusable UI components.
The React team announced the release plan for the upcoming stable version of React 18. Now, it is in beta.
In this article, we are going to discuss some of the marvelous feature updates for React version 18 with code examples.
Introducing the new root API
A root in React refers to the top-level data structure that renders a tree. In React 18, we will have two root APIs: the legacy root API and the new root API.
Legacy root API
The legacy root API is the existing API called with the ReactDOM.render method. It will create a root running in legacy mode, which is similar to usage in React version 17. Before moving React 18 to production, a warning will be added on the usage of the legacy root API. It will gradually enforce the usage of the new root API. The legacy root API will be deprecated in upcoming versions.
Refer to the following code example.
import * as ReactDOM from 'react-dom'; import App from 'App'; const container = document.getElementById(‘root’); // Initial render. ReactDOM.render(<App tab="home" />, container); // During an update, React will access the container element again. ReactDOM.render(<App tab="profile" />, container);
Syncfusion React UI components are the developers’ choice to build user-friendly web applications. You deserve them too.
New root API
The new root API will be invoked with the ReactDOM.createRoot method. To use it, first, we have to create the root through the createRoot method with the root element as an argument. Then, we call the root.render method and pass the app component as the parameter. By using the new root API, we can use all the enhancements and concurrent features available in React 18.
Refer to the following code.
import * as ReactDOM from 'react-dom'; import App from 'App'; // Create a root. const root = ReactDOM.createRoot(document.getElementById('root')); // Initial render: Render an element to the root. root.render(<App tab="home" />); // During an update, there's no need to access the container again since we have already defined the root instance. root.render(<App tab="profile" />);
Changes in hydrate method
The hydrate method is similar to the render method. But it helps to attach event listeners to the HTML elements within the containers that are rendered by the ReactDOMServer method on the server side.
React 18 replaces this hydrate method with the hydrateRoot method.
Refer to the following code example.
import * as ReactDOM from 'react-dom'; import App from 'App'; const container = document.getElementById('app'); // Create and render a root with hydration. const root = ReactDOM.hydrateRoot(container, <App tab="home" />); // Unlike the createRoot method, you don't need a separate root.render() call here.
Changes in render callback
The render callback is removed from the new root API. But we can pass it as property to the root component.
Refer to the following code example.
import * as ReactDOM from 'react-dom'; function App({ callback }) { // Callback will be called when the div element is first created. return ( <div ref={callback}> <h1>Hello </h1> </div> ); } const rootElement = document.getElementById("root"); const root = ReactDOM.createRoot(rootElement); root.render(<App callback={() => console.log("renderered")} />);
A to Z about Syncfusion’s versatile React components and their feature set.
Improvement in automatic batching
The batching feature in React 18 merges multiple state updates into a consolidated single rerender for improved performance. For instance, if we update more than one state value in a simple function handler. Then, React 18 will batch these updates into a single update and rerender the app only once instead of calling the render method multiple times.
This will considerably improve the app’s overall performance. It also prevents components from rendering with incomplete state updates where only one state variable is updated, which may lead to irrelevant behavior in the app.
Refer to the following code example.
function App() { //Declaring state values. Const [count, setCount] = useState(0); const [flag, setFlag] = useState(false); // Change state on button click. function handleClick() { setCount(c => c + 1); // Does not re-render yet setFlag(f => !f); // Does not re-render yet // React will only re-render once at the end (that’s batching!) } return ( <div> <button onClick={handleClick}>Next</button> <h1 style={{ color: flag ? “blue” : “black” }}>{count}</h1> </div> ); }
React 18 will automatically batch all the state updates, irrespective of where they originate. Therefore, if any update is inside a timeout, promise, native event handler, or any other event, the React 18 version will batch it in the same way as updates inside React events. This will further improve the performance of the app and lead to fewer re-renderings of the components compared to the previous React versions.
Refer to the following code.
function App() { const [count, setCount] = useState(0); const [flag, setFlag] = useState(false); function handleClick() { fetchSomething().then(() => { // React 18 and later versions batch these state updates with single rerendering. setCount(c => c + 1); setFlag(f => !f); // React will rerender once at the end (that's batching!) }); } return ( <div> <button onClick={handleClick}>Next</button> <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1> </div> ); }
Disable automatic batching
Sometimes, we need to immediately rerender the component after each state change. In that scenario, use the flushSync method to disable the automatic batching.
import { flushSync } from 'react-dom'; // Note: react-dom, not react function handleClick() { flushSync(() => { setCounter(c => c + 1); }); // React has updated the DOM by now. flushSync(() => { setFlag(f => !f); }); // React has updated the DOM by now. }
Suspense
We can accomplish server-side rendering in React by rendering all the components on the server first. Then, we have to send the results as HTML elements to the browser.
In the browser, React will load JavaScript as usual. Then it will connect the HTML elements generated from the server with the JavaScript and hydration logic.
The server-side rendering (SSR) allows us to see the page content before the JavaScript bundle loads and runs.
The suspense feature will delay the rendering of components in React. It was first introduced in React version 16.6 with certain limitations and basic support for suspense rendering.
React 18’s stable version will support the full-fledged suspense feature based on the concurrent feature, along with the following:
- Delayed transition: Instructs the components to wait for the data to be resolved before proceeding with a new state transition.
- Placeholder throttling: Reduces UI thrash by throttling the appearance of nested placeholder and successive placeholder components.
- SuspendList: Helps suspend many components by arranging them in the order in which these components need to be revealed to the user.
React 18 handles suspense differently from the previous versions. This seems to be a breaking change. But with automatic batching, the impact of the change is minimum. It will not affect the migration process of the app to React version 18 significantly.
Earlier, the suspense feature in React 16 and 17 was called legacy suspense. The enhanced suspense in the React 18 is called concurrent suspense.
In general, both the legacy and concurrent suspense features offer the same basic user experience, apart from resolving the ComponentThatSuspends method, as in the following example.
<Suspense fallback={<Loading />}> <ComponentThatSuspends /> <Sibling /> </Suspense>
This example is a simple explanation of how a suspense component will work in the older and new React 18 versions:
- The legacy suspense will immediately mount the Sibling component to the DOM. Also, its lifecycle hooks/effects will be fired. It won’t wait for the ComponentThatSuspends to be resolved.
- The concurrent suspense won’t mount the Sibling component to the DOM and its lifecycle hooks/effects will not be fired until the ComponentThatSuspends is resolved. This new enhancement will resolve all the existing issues in the legacy suspense.
See the possibilities for yourself with live demos of Syncfusion React components.
Concurrency
Concurrency allows you to execute multiple tasks at the same time. For instance, let’s take a standard React app. While executing an animation action in a component, concurrency will allow UI interaction with the other React components at the same time.
Previously, only one setState update was possible at a time, and all the updates had the same priority. The new concurrent feature with the startTransition API will mark all the updates as non-urgent. Based on the given priority, React will interrupt them or put them on hold.
Note: There will be no out-of-the-box breaking changes in the component behavior related to concurrency in React 18. So, we can choose whether to use it or not.
GitHub reference
For more details, refer to the following GitHub references:
- New Suspense SSR Architecture in React 18
- Five significant features of React 18
- Concurrent React for Library Maintainers
Explore the endless possibilities with Syncfusion’s outstanding React UI components.
Conclusion
Thanks for reading! The upcoming React 18 stable version will bring an exciting new set of features for the developer community. The main focus is on concurrency and gradual up-gradation to the newer version. Since it is still in beta, the React team created a working group to prepare the ecosystem for the smooth transition to the new version.
Syncfusion React JS UI components will always be compatible with the latest React versions. We will include support for React 18 after it becomes production-ready.
For existing customers, the newest Essential Studio version is available for download from the License and Downloads page. If you are not yet a Syncfusion customer, you can try our 30-day free trial to check out the available features. Also, check out our demos on GitHub.
You can contact us through our support forums, support portal, or feedback portal. We are always happy to assist you!