Unpacking the Power of Concurrent Rendering and Features in React 18

React 18, which hit beta in November, brings forth an array of new features and enhancements that promise to reshape the way we build web applications. A standout feature is Concurrent Features, which leverages concurrent rendering to take user experiences to the next level.

Demystifying Concurrency in React

Concurrent rendering, a central concept in React 18, introduces the notion of executing multiple tasks simultaneously. These tasks can overlap, with React intelligently prioritizing the more urgent ones. To illustrate, consider a scenario where I’m writing this post while simultaneously preparing a sumptuous Nigerian delicacy, Jollof rice. If the cooking demands immediate attention, I’ll momentarily pause writing, attend to the cooking, and then return to continue my writing. Throughout this process, I’ll naturally focus on the more pressing task at hand.

In the past, React operated under the constraints of Blocking Rendering, meaning it could only handle one task at a time without interruption. However, Concurrent Mode was introduced to remedy this limitation by making rendering interruptible.

The Transition from Concurrent Mode

Initially introduced as an experimental feature, Concurrent Mode is gradually giving way to a more adaptable approach in React 18. This transition empowers developers to selectively embrace concurrent rendering, aligning with their project’s requirements, at their own pace. The new approach is referred to as concurrent features.

Concurrent Rendering and Its Relationship with Concurrent Features

Concurrent rendering serves as the underlying mechanism powering the new concurrent features introduced in React 18. With concurrent rendering, developers can optimize their applications by marking certain state updates as non-urgent, thereby ensuring a responsive browser. This optimization is automatically enabled for the specific parts of your application that leverage the new concurrent features, as they are built upon the foundation of concurrent rendering.

The startTransition API

One of the standout additions in React 18 is the startTransition API. This API facilitates maintaining the responsiveness of your application without obstructing user interactions. It allows you to designate specific updates as transitions, which are considered non-urgent and can be suspended or interrupted by more pressing urgent updates.

For instance, imagine a search input field where users expect instant feedback as they type. With startTransition, you can ensure that the search results, which may take a bit longer to fetch, do not disrupt the smooth typing experience.

import { startTransition } from 'react';

// Mark any state updates inside as transitions
startTransition(() => {
  // Transition
  setSearchQuery(input);
})

In React 18, all updates are treated as urgent by default. However, you can explicitly mark an update as a transition by wrapping it in the startTransition API.

The useTransition API

React 18 also introduces the useTransition hook, which allows you to track and manage pending state transitions using an isPending flag. This feature empowers you to provide users with feedback indicating that background work is in progress, thereby enhancing their overall experience.

import { useTransition } from 'react';

const [isPending, startTransition] = useTransition();

{isPending && <Spinner />}

The useDeferredValue API

Another valuable addition is the useDeferredValue API. This API ensures the responsiveness of your UI by instructing React to defer updates for parts of the screen that may take a while to render. For instance, you can display an old value while a more time-consuming component updates.

import { useState, useDeferredValue } from "react";

function App() {
  const [input, setInput] = useState("");
  const deferredValue = useDeferredValue(text, { timeoutMs: 3000 }); 

  return (
    <div>
      <input value={input} onChange={handleChange} />
      <MyList text={deferredValue} />
    </div>
  );
 }

In this example, the input value appears immediately as a user types, but the useDeferredValue API retains the previous version of the MyList component for a maximum of 3000 milliseconds.

Server-side rendering (SSR)

Server-side rendering (SSR) has long been a game-changer in web development, allowing developers to generate HTML from React components on the server and send fully rendered HTML pages to clients. While these pages lack interactivity, they provide users with content to view before the JavaScript bundle loads. Subsequently, React and JavaScript code begin loading, connecting the client-side logic to the server-generated HTML—a process known as hydration.

Historically, in previous versions of React, the hydration process could only commence after all data had been fetched from the server and rendered to HTML. Unfortunately, users were unable to interact with the page until hydration was complete for the entire page. This approach resulted in inefficiencies, with fast-loading parts of an application waiting for slower sections to load.

React 18 has addressed this issue by introducing support for Suspense on the server. Suspense, initially released in 2018 for lazy-loading client-side code, now offers server-side capabilities. React 18 unlocks two essential SSR features through Suspense:

Streaming HTML on the Server

With Suspense, developers can wrap specific parts of a page and provide a fallback prop. Suspense acts as a directive, specifying what should occur when code for a component is not yet ready or is taking an extended time to load. This instructs React to continue streaming HTML for the remaining page, rather than waiting for the delayed component. While waiting, React displays the provided fallback component to users.

<Layout>
  <Article />
  <Suspense fallback={<Spinner />}>
    <Comments />
  </Suspense>
</Layout>

In this code snippet, the Comments component is wrapped in a Suspense boundary with a specified fallback (Spinner). React proceeds to render the Article, and once the server-side HTML for Comments becomes available, it appends it to the stream, accompanied by a script tag, placing it in the correct location.

Selective Hydration

Similar to the previous example, employing Suspense for the Comments component enables React to prioritize streaming the HTML for the Article component without blocking hydration or waiting for all JavaScript code to load. This means React can begin hydrating the remaining page, and when the HTML for the Comments section is ready, it will be seamlessly hydrated.

<Layout>
  <Article />
  <Suspense fallback={<Loader />}>
    <Comments />
    <Card />
  </Suspense>
</Layout>

A noteworthy improvement in Suspense is that if a user interacts with a Suspense-wrapped component whose HTML has been loaded but not yet hydrated, React will prioritize hydrating the interactive parts first before proceeding with the rest of the app.

Opting into Concurrency

To leverage these features, upgrading React and ReactDOM to version 18 is essential. Additionally, moving from ReactDOM.render to ReactDOM.createRoot marks your entry into concurrent rendering for parts of your app that utilize concurrent features.

import * as ReactDOM from 'react-dom';
import App from 'App';
const container = document.getElementById('app');
// Create a root
const root = ReactDOM.createRoot(container);
// Initial render
root.render(<App />);

This new root API not only facilitates concurrency but also provides access to concurrent features out of the box.

Conclusion

In this exploration, we delved into the realm of concurrent rendering in React 18 and the subsequent emergence of concurrent features. By opting into concurrency, developers can harness the power of Suspense on the server, streamlining the rendering and hydration processes for a more efficient and responsive user experience. As React 18 continues to evolve, these advancements promise to reshape web development practices, ensuring that user interactions are smooth and uninterrupted.

Recommended:

Different Types of Variables in Java

Variables in Java: A Beginner’s Guide

Understanding Static Variables in Java

Let’s Understanding Instance Variables in Java

Understanding Local Variables in Java

Creating and Using Variables in Java

Understanding Java Data Types with Examples

Java Primitive Data Types and Variables

How to Compile and Run a Java Program from Command Prompt

Structure of Java: An Overview

Programming in Java: A Beginner’s Guide

Java: A Versatile Programming Language for the Modern World

Exploring the Powerful Features of Java

Exploring the Java Development Kit (JDK)

Guide on How to Download Java

Reference:

learnwithshikha20@insta

learnwithshikha@facebook

Leave a Comment