React is an open source JavaScript library that developers use to create Web-based and mobile applications and support building interactive user interfaces and UI components. React was created by Facebook software engineer Jordan Walke. The first version of React came out seven years ago and is now maintained by Facebook. The React framework has skyrocketed in popularity since it was first released. React 17 was released in October 2020, but surprisingly — with “zero new features.” Of course, this doesn’t really mean that there aren’t any new additions to excite the programmer user base. In fact, this release brings us a number of major feature updates and bug fixes in version 16, with Concurrent Mode and Suspense. Although these two features have not been officially released, they are available for developers to test. Once released, they will change the way React presents its UI, doubling the performance and user experience.
In Suspense, Concurrent Mode and Suspense allow users to handle data loading and loading state seamlessly, making user interface operations smoother and seamless. In Concurrent Mode, React can suspend rendering of high-consumption, non-urgent components and focus on more pressing tasks such as UI rendering, always keeping the application responsive and avoiding white screens, stuttering, etc.
This article focuses on providing insight into data extraction functions in Concurrent Mode and Suspense Mode.
Why a Concurrent Mode?
It is well known that JavaScript frameworks or libraries are single-threaded work. Therefore, while one code block is running, the rest of the blocks must wait to execute. Unable to execute multithreaded work concurrently. The same is true for interface rendering. Once React starts rendering something, it can’t be interrupted until the run is done. React developers call this “blocking rendering.” This blocking rendering creates an unstable user interface that can stop responding at any time.
Specific problems
Suppose we need to display a long list of optional applications for filtering products. We use the search box to filter records, and the design is that when the user clicks the search button, the user interface needs to refresh to list the associated data.
If the list is too long and there is too much data, the UI “stutters,” or renders are visible to the user. Such latons can also significantly degrade product performance. There are techniques developers can use, such as throttling and stabilization, that can help but are not perfect solutions. Throttling limits the number of times a particular function can be called. Using throttling, we can avoid repeated calls to expensive and time-consuming apis or functions. This process improves performance, especially in the presentation of information in the user interface.
Stabilization ignores function calls for a predetermined amount of time. Function calls are made only after a predetermined time.
The following diagram depicts the lag phenomenon: THE UI freezes while waiting for non-urgent API calls to complete, preventing the user interface from rendering. The solution is to use concurrent mode for interruptible rendering.
Uninterrupted rendering
With interruptible rendering, react.js does not block the UI while processing and rerendering lists. It makes react.js more granular by pausing trivial work, updating the DOM, and making sure the UI doesn’t get stuck. React uses user input to update or redraw input boxes in parallel. React executes in parallel using user input and redraw input boxes. It also updates the list in memory. When React completes the update, it updates the DOM and rerenders the list on the user’s monitor. Essentially, interrupt-free rendering enables React to “multitask.” This feature provides a smoother UI experience.
Concurrent mode
Concurrency mode is a set of features that help React applications stay responsive and smoothly adapt to the user’s device and network speed capabilities. The concurrent mode divides the tasks it owns into smaller chunks. The React scheduler can pick and choose which jobs to execute. Jobs are scheduled depending on their priority. By prioritizing tasks, it can stop trivial or non-urgent things, or push them further. React always prioritizes user interface updates and rendering.
Using concurrent mode, we can:
- Controls the first rendering process
- Prioritize the rendering process
- Pause and resume rendering of components
- Cache and optimize runtime rendering of components
- Hide the display until it needs to be displayed
With UI rendering, concurrent mode improves response to incoming data, lazy loading of controls, and asynchronous processing. Concurrent mode keeps the user interface active and updates data in the background. Concurrent mode also uses the React hooks: useTransition and useDeferredValue
Using useDeferredValue Hook
UseDeferredValue Hook is defined as follows:
const deferredValue = useDeferredValue(value, { timeoutMs: <some value> });
Copy the code
This command sets the value “lag” after the time set in timeoutMs. Whether the user interface must be updated immediately or must wait for data, this command keeps the user interface active and responsive. The Hook avoids UI lag and always keeps the user interface responsive to keep the cost of retrieving data low.
Use the Transition Hook
UseTransition Hook is a Hook that is used to suspend a user in React. With the click of a button, the web page displays the user’s details on the screen. Suppose the user clicks one button first, and then the next. The screen either goes blank or we see a spinner on the screen. If it takes too long to get the details, the user interface may freeze. The useTransition method returns two hooks: startTransition and isPending. The syntax for this definition is as follows:
const [startTransition, isPending] = useTransition({ timeoutMs: 3000 });
Copy the code
StartTransition defines the syntax:
<button disabled={isPending} startTransition(() => { <fetch Calls> }); </button> {isPending? " Loading..." : null}Copy the code
Using the useTransition hook, react.js continues to display the user interface without user details until the user details are ready, but the UI is responsive. React prioritizes the user interface to remain responsive while retrieving data in parallel.
Suspense for getting data
Suspense is another experimental feature introduced with concurrency modes in React. Suspense makes it possible for components to wait a predetermined amount of time before rendering. Suspense’s main purpose is to read data asynchronously from components without worrying about the source of the data. Suspense is best suited to the concept of lazy loading. Suspense allows the data fetch library to inform React whether a data component is available. React will not update the UI until the necessary components are in place.
Benefits of using Suspense:
1. Integration between the Data acquisition library and the React component
2. Control the visual loading state
3. Avoid competing conditions
The basic syntax for Spinner components is as follows:
import Spinner from './Spinner';
<Suspense fallback={<Spinner />}>
<SomeComponent />
</Suspense>
Copy the code
Suspense, used in Concurrent Mode, allows time-consuming components to start rendering while waiting for data. Display placeholders as well. This combination results in a smoother UI experience.
Suspense and lazy load components
React.lazy is a new feature that enables react. js to lazily load components. Lazy loading means that components are loaded (the code to retrieve and render them) only when needed. They prioritize the most critical user interface components. The React developers recommend wrapping lazy-loaded components in Suspense components. Doing so ensures that the component does not appear in a “bad state” when rendered. The user interface remains responsive throughout the process and leads to a smoother user experience.
Enable concurrent mode
To enable concurrent mode, install the latest test version. The prerequisite for installing React is the Node Packet Manager (NPM). To install the test version, execute the following command:
npm install react@experimental react-dom@experimental
Copy the code
To test if a test version is set up, create a sample React application. The rendering code without testing is as follows:
import * as React from 'react';
import { render } from 'react-dom';
render(<App />, document.getElementById('root'));
Copy the code
In concurrent mode, the specific code is as follows:
import * as React from 'react';
import { createRoot } from 'react-dom';
createRoot(document.getElementById('root')).render(<App />);
Copy the code
This will enable concurrent mode for the entire application. React splits the render call into two parts:
- Create the root element
- Using render calls
React currently plans to maintain three modes:
- The legacy schema is backward compatible with the legacy or current schema
- The blocking pattern is an intermediate stage in the development of the concurrent pattern
- Concurrent mode
The blocking mode replaces the createRoot call with the createBlockingRoot call, and in the case of concurrent development, the blocking mode provides the developer with an opportunity to fix bugs or resolve problems.
The React documentation also explains what each mode supports:
Example applications:
This article also created a test program to verify the use and effects of the concurrent pattern and other patterns. This paper takes pixel application as an example. Pixels are randomly distributed on a 150*150 canvas and a search box is included. Every time the user clicks the search box, the canvas will re-render itself. Even if the UI cannot be rendered in concurrent mode, user input does not stop updating. The pixel canvas is rerendered after the processing is complete. In traditional mode, the UI stops when you type quickly, sometimes before rendering the canvas again. User input also stops and is not updated.
The main file for building pixel applications is canvas.js. We also made an input box where the user could enter anything. The pixel canvas is rerendered each time a key is pressed.
Code examples:
- Index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
// Traditional or non-Concurrent Mode react
const rootTraditional = document.getElementById("root");
ReactDOM.render(<App caption="Traditional or Block Rendering" />,
rootTraditional);
// Concurrent Mode enabled
const rootConcurrent = document.getElementById("root-concurrent");
ReactDOM.createRoot(rootConcurrent).render(<App caption="Interruptible
Rendering" />);
Copy the code
- App.js
import React, { useState, useDeferredValue } from "react";
import "./App.css";
import { Canvas } from "./Canvas";
export default function App(props)
{ const [value, setValue] = useState("");
//This is available only in the Concurrent mode.
const deferredValue = useDeferredValue(value, {
timeoutMs: 5000
});
const keyPressHandler = e => {
setValue(e.target.value);
};
return (
<div className="App">
<h1>{props.caption}</h1>
<input onKeyUp={keyPressHandler} />
<Canvas value={deferredValue} />
</div>
);
}
Copy the code
- Canvas.js
import React from "react";
const CANVAS_SIZE = 70;
const generateRandomColor = () => {
var letters = "0123456789ABCDEF";
var color = "#";
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
const createCanvas = (rows, columns) => {
let array = [];
for (let i = 0; i < rows; i++) {
let row = [];
for (let j = 0; j < columns; j++) {
row.push(0);
}
array.push(row);
}
return array;
};
//This is the square with the pixels
const drawCanvas = value => {
const canvas = createCanvas(CANVAS_SIZE, CANVAS_SIZE);
return canvas.map((row, rowIndex) => {
let cellsArrJSX = row.map((cell, cellIndex) => {
let key = rowIndex + "-" + cellIndex;
return (
<div
style={{ backgroundColor: generateRandomColor() }}
className="cell"
key={"cell-" + key}
/>
);
});
return (
<div key={"row-" + rowIndex} className="canvas-row">
{cellsArrJSX}
</div>
);
});
};
export const Canvas = ({ value }) => {
return (
<div>
<h2 style={{ minHeight: 30 }}>{value}</h2>
<div className="canvas">{drawCanvas(value)}</div>
</div>
);
};
Copy the code
- Index.html
<! DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <meta name="theme-color" content="#000000" /> <title>React App Concurrent Mode</title> </head> <body> <noscript> You need to enable JavaScript to run this app. </noscript> <div id="container"> <div id="root" class="column"></div> <div id="root-concurrent" class="column"></div> </div> </body> </html>Copy the code
Run the example
Let’s look at our code. The first screen we see is the initial screen. Using traditional or block rendering is what React does now. Interruptible rendering is a test feature in concurrent mode. Let’s look at traditional rendering work first.
The pixel canvas is rerendered with each keystroke. In traditional rendering, the entire UI pauses with each keystroke until it can re-render the screen. In the meantime, user input will not be updated even if we continue typing.
The following image shows interruptible rendering. In interruptible rendering, the user can continue typing. The UI does not stop or stop as the canvas is rerendered in parallel for each keystroke.
React will update the UI after the re-rendering is complete. While it’s hard to see in static screenshots, we can see that the grid is changing, but the user can still type without the UI getting stuck.
conclusion
In this article, we looked at the test concurrency features of React and Suspense. With concurrent mode, react.js always keeps the user interface responsive. It breaks down the application’s tasks into smaller chunks and allows prioritization of user interface tasks. As a result, this pattern provides a smoother and seamless user experience and improves the overall performance of the application.
In conjunction with the concurrent mode, Suspense allows the user interface to remain responsive. At the same time, heavy and time-consuming tasks such as data acquisition can be done in parallel, providing an overall seamless experience.
Full details on the concurrency mode can be found in the React documentation. With the improvement of React version, React framework is becoming more and more familiar to Chinese front-end developers and widely used in their project development. It is another popular mainstream framework for the front end after vue. js. Now, it has derived many functional tools that support integration with the React framework, such as the ActiveReportsJS control, which provides an online editor and report display tool that integrates directly with React to improve the front end data display function.