React is an open source JavaScript library that developers use to create web and mobile-based applications, and supports the construction of 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. Now, Facebook is responsible for maintenance. Since the first release of the React framework, the popularity of React has soared and its popularity has not diminished.
In October 2020, React 17 was released, but it was surprisingly "zero new features". Of course, this does not really mean that there are no newly added features that will excite the majority of programmer users. In fact, this version has brought us a lot of major feature upgrades and bug fixes in version 16, and introduced: Concurrent Mode and Suspense.
Although these two features have not yet been officially released, these features have been provided to developers for testing. Once released, they will change the way React presents its UI, which will double the performance and user experience.
Briefly, Concurrent Mode and Suspense can enable users to seamlessly process data loading and loading status, and the user interface operation is smoother and seamless switching. In Concurrent Mode, React can suspend the rendering of high-consumption, non-urgent components, and focus on more urgent task processing, such as UI rendering, and always keep the application responsive, avoiding white screens, freezes and other phenomena.
This article mainly shares an in-depth understanding of the data extraction function in Concurrent Mode and Suspense Mode.
Why do I need Concurrent Mode?
As we all know, JavaScript frameworks or libraries are single-threaded jobs. Therefore, when a code block is running, the remaining blocks must wait for execution. It is not possible to perform multithreaded work concurrently. The interface rendering is the same.
Once React starts rendering something, it cannot be interrupted until the run is complete. React developers call this type of rendering "blocking rendering." This blocking rendering creates an unstable user interface and may stop responding at any time.
specific problem
Suppose, we need to display a long list of optional applications for filtering products. We use the search box to filter records. The design solution is that when the user clicks the search button, the user interface needs to be refreshed to list the associated data.
If the list is too long and there is too much data, the UI "stutters", that is, the rendering is visible to the user. This kind of lag will also greatly reduce product performance. Developers can use some technologies, such as throttling and anti-shake. These technologies will help, but they are not a perfect solution.
Throttling limits the number of times a specific function is called. Using throttling, we can avoid repeatedly calling expensive and time-consuming APIs or functions. This process can improve performance, especially the presentation of information on the user interface.
Anti-shake will ignore the call to the function within a predetermined time. The function call is only performed after a predetermined time has elapsed.
The following figure describes the stuttering phenomenon:
While waiting for the completion of the non-urgent API call, the UI freezes, preventing the presentation of the user interface. The solution is to use concurrent mode for interruptible rendering.
Non-stop rendering
With interruptible rendering, React.js will not block the UI while processing and re-rendering the list. It makes React.js more detailed by suspending trivial work, updating the DOM, and ensuring that the UI does not freeze. React uses user input to update or redraw input boxes in parallel. React uses user input and redraws the input box to execute in parallel. It also updates the list in memory. After React finishes updating, it updates the DOM and re-renders the list on the user's display. In essence, non-disruptive rendering enables React to "multitask." This feature provides a smoother UI experience.
Concurrent mode
Concurrent mode is a set of features that help React applications remain responsive and smoothly adapt to the user's device and network speed capabilities. Concurrent mode divides the tasks it owns into smaller blocks. React's scheduler can pick and choose the job to be executed. The scheduling of jobs depends on their priority. By prioritizing tasks, it can stop trivial or non-urgent things, or push them further. React always puts user interface update and rendering in the first place.
Using concurrent mode, we can:
- Control the first rendering process
- Prioritize the rendering process
- Pause and resume component rendering
- Cache and optimize runtime rendering of components
- Hide the displayed content until it needs to be displayed
With UI rendering, the concurrent mode improves the response to incoming data, lazy loading of controls, and asynchronous processing. Concurrent mode ensures that the user interface is always active, and data is continuously updated in the background. Concurrent mode also always uses React's two hooks: useTransition
and useDeferredValue
Use useDeferredValue Hook
useDeferredValue Hook
is as follows:
const deferredValue = useDeferredValue(value, { timeoutMs: <some value> });
The value set by this command "lags" after the time 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 freezes, and always keeps the user interface responsive to keep the cost of acquiring data lagging low.
Use Transition Hook
useTransition Hook
is React
mainly used for suspension in Hook
. Suppose that there is a webpage with a user name button. Just click a button and the web page will display the user's detailed information on the screen.
Suppose the user first clicks a button and then clicks the next. The screen either goes blank or we see a spinner on the screen. If it takes too long to obtain detailed information, the user interface may freeze.useTransition
method returns two Hook
values: startTransition
and isPending
. The defined syntax is as follows:
const [startTransition, isPending] = useTransition({ timeoutMs: 3000 });
The syntax defined by startTransition
<button disabled={isPending}
startTransition(() => {
<fetch Calls>
});
</button>
{isPending? " Loading...": null}
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 maintain responsiveness while fetching data in parallel.
Suspense for data acquisition
Suspense
is React
together with the concurrent mode. Suspense
enables the component to wait a predetermined period of time before rendering.Suspense
is to asynchronously read data from the component without worrying about the source of the data. Suspense
most suitable for the concept of lazy loading. Suspense
allows the data acquisition library to notify React
whether the data component can be used. Until the necessary components are ready, React
will not update the UI.
Benefits of using Suspense
1. Integration between data acquisition library and React
2. Control the visual loading state
3. Avoid race conditions
The basic syntax of the Spinner
import Spinner from './Spinner';
<Suspense fallback={<Spinner />}>
<SomeComponent />
</Suspense>
Concurrent Mode
used in Suspense
allows time-consuming components to start rendering while waiting for data. Also display placeholders. This combination produces a smoother UI experience.
Suspense and lazy loading components
React.lazy
is a new feature that enables React.js
to lazily load components. Lazy loading means loading components (code to retrieve and render them) only when needed. They will prioritize the most critical user interface components. React
developer recommends packaging the lazy loading component in the Suspense
component.
Doing so ensures that the component does not appear "bad state" when it is rendered. The user interface remains responsive throughout the process and brings a smoother user experience.
Enable concurrent mode
To enable concurrent mode, please install the latest test version. The prerequisite for installing React is the Node Package Manager (npm). To install the test version, execute the following command:
npm install react@experimental react-dom@experimental
To test whether a test version is set, create a sample React application. The rendering code without the test function is as follows:
import * as React from 'react';
import { render } from 'react-dom';
render(<App />, document.getElementById('root'));
In the concurrent mode, the specific code is as follows:
import * as React from 'react';
import { createRoot } from 'react-dom';
createRoot(document.getElementById('root')).render(<App />);
This will enable concurrent mode for the entire application. React divides the rendering call into two parts:
- Create the root element
- Use render calls
Currently, React plans to maintain three modes:
- Legacy mode is the traditional or current mode that is backward compatible
- Blocking mode is the intermediate stage of concurrent mode development
- Concurrent mode
The blocking mode uses the createBlockingRoot call to replace the createRoot call. In the case of concurrent development, the blocking mode provides developers with opportunities to fix bugs or solve problems.
The official React documentation also explains the functions supported by each mode:
Sample application:
This article also created a test program to verify the usage and effects of concurrent mode and other modes. This article uses pixel applications as an example to randomly distribute pixels on a 150*150 canvas and include a search box. Each time the user clicks the search box, the canvas will re-render itself.
Even if the UI interface cannot be rendered in concurrent mode, user input will not stop updating. The pixel canvas is re-rendered after processing. In traditional mode, the UI will stop when typing quickly, sometimes before rendering the canvas again. User input will also stop and will not update.
The main file for building a pixel application is canvas.js. We also made an input box in which users can input anything. The pixel canvas is re-rendered every time a key is pressed.
Code example:
- 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" />);
- 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>
);
}
- 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>
);
};
- 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>
Run example
Let's take a look at our code. The first screen we see is the initial screen. Using traditional or block rendering is now React's approach. Interruptible rendering is a test feature of concurrent mode. Let's first look at the traditional rendering work.
The pixel canvas is re-rendered with every keystroke. In traditional rendering, the entire UI will pause at each keystroke until it can re-render the screen. During this period, even if we continue typing, user input will not be updated.
The image below shows interruptible rendering. In interruptible rendering, the user can continue to input. When re-rendering the canvas in parallel for each keystroke, the UI does not stop or stop.
After the re-rendering is complete, React will update the UI. Although it is difficult to see in static screenshots, we can see that the grid is changing, but the user can still type without UI freezes.
to sum up
In this article, we studied React's test concurrency function and Suspense. Using concurrent mode, React.js always keeps the user interface responsive. It breaks down the tasks of the application into smaller pieces and allows prioritization of user interface tasks. Therefore, this mode can provide a smoother and seamless user experience and improve the overall performance of the application.
Combined 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 completed in parallel to provide an overall seamless experience.
Full details about the concurrency mode can be found in the official React documentation.
With the improvement of the React version, the React framework is becoming more and more well-known by more Chinese front-end developers and widely used in their project development. It is another popular front-end mainstream framework after continuing Vue.js. Now it has derived many functional tools that support integration with the React framework, such as the front-end report ActiveReportsJS control, SpreadJS pure front-end report control, etc., providing direct integration with React The online editor and report design tool, perfect the front-end data display function.
SpreadJS pure front-end table control
SpreadJS is a pure front-end table control based on HTML5, which can be embedded in various applications natively and combined with the front-end and back-end technical framework. Integrating SpreadJS with React can implement Excel-like spreadsheet functions in the React framework, including support for more than 450 calculation formulas, online import and export of Excel documents, pivot tables, and various data visualization effects, making the application extremely powerful Data processing performance and response speed.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。