Unlocking the Power of React 18: A Deep Dive into Concurrent Rendering

The Future of React is Here

React 18 is revolutionizing the React ecosystem with its highly-anticipated concurrent rendering features. Since the React team announced the plan for React 18 in June 2021, the community has been eagerly waiting for its release. At React Conf 2021, the team unveiled the new concurrent rendering features, which have been generating a lot of buzz. To fully harness the power of React 18, it’s essential to understand the new APIs that come with it.

Getting Familiar with Concurrent Rendering

Before we dive into the new APIs, it’s crucial to have a solid understanding of concurrent rendering. If you’re new to the concept, start by checking out the React 18 announcement or the working group announcement. This will provide a solid foundation for the rest of the article.

useSyncExternalStore: Efficiently Integrating with External Data Sources

One of the new APIs introduced in React 18 is useSyncExternalStore. This Hook allows React components to safely and efficiently integrate with external mutable sources during concurrent rendering. It’s an evolution of useMutableSource, which was introduced in React v16.14.0.

The Challenges of useMutableSource

useMutableSource had some significant limitations. Firstly, it was naturally asynchronous, which led to performance issues. Secondly, it had to deal with external state, which could change at any time, causing suboptimal user experiences.

The Solution: useSyncExternalStore

To address these issues, the React team revamped the underlying implementation and renamed the Hook to useSyncExternalStore. The changes include:

  • Not re-subscribing to the external source every time the selector changes
  • Ensuring that updates are always synchronous, preventing the UI from being replaced with a fallback

How to Use useSyncExternalStore

To use useSyncExternalStore, simply pass a function that returns the current value of the external store. The Hook will then compare the resulting values of the selectors to decide whether to retrieve the snapshot again.

useId: Generating Unique Identifiers for Server-Side Rendering

useId is another new API introduced in React 18. It generates stable identifiers during server-side rendering (SSR) and hydration, ensuring that mismatches are avoided.

The Evolution of useOpaqueIdentifier

Initially, React introduced useOpaqueIdentifier, but it had some issues. The Hook would produce different outputs in different environments, and it couldn’t generate new IDs dynamically.

The Solution: useId

To address these issues, the implementation was changed and renamed to useId. This new Hook API generates stable identifiers during SSR and hydration, falling back to a global counter outside of server-rendered content.

How to Use useId

To use useId, simply call the Hook once and use it as a base for generating unique identifiers throughout your component.

useInsertionEffect: Optimizing CSS-in-JS Libraries

useInsertionEffect is the last Hook we’ll discuss. Its primary purpose is to optimize CSS-in-JS libraries that generate new rules on the fly and insert them with <style> tags in the document.

The Problem with CSS-in-JS Libraries

When CSS rules are added or removed, the browser has to recalculate all style rules and reapply them, which can cause performance issues in concurrent rendering.

The Solution: useInsertionEffect

To address this, the React team introduced useInsertionEffect. This Hook is similar to useLayoutEffect, but it doesn’t have access to refs of DOM nodes, making it perfect for inserting global DOM nodes like <style> or SVGs <defs>.

Final Thoughts

React 18 is packed with new features, and its concurrent rendering capabilities are revolutionizing the way we build React applications. By understanding the new APIs, including useSyncExternalStore, useId, and useInsertionEffect, you’ll be able to unlock the full potential of React 18. Get ready to take your React skills to the next level!

Leave a Reply

Your email address will not be published. Required fields are marked *