4
头图

Passing by: React17

New features of React17: For users, there are no new features, official words:

The React 17 release is unusual because it doesn't add any new developer-facing features. Instead, this release is primarily focused on making it easier to upgrade React itself.

Event system refactoring

As an in-depth user of the React library, I personally like this All In Js development method. The entire page logic can be written in js instead of constantly switching between html and js and designing each other;

But another important point is that the development process does not need to consider the cross-browser compatibility of events, because React has made mainstream browser compatibility through SyntheticEvent.

Although the usage is mostly the same, it is not exactly the same as the native event. The differences are:

  • The mounting mechanism of event nodes, React uses all node events to be mounted on the document node, and adopts the mechanism of event delegation and registration distribution;
  • The timing of event triggering is inconsistent. Although they all follow the downward capture and upward bubbling, the synthetic event will be 晚一拍 ; the specific performance is, native event capture -> native event bubbling -> react event capture -> react event bubbling Bubble;
  • The input parameters of the callback event are different. The native one is the event object, and the React one is the synthetic event object, and it has its own event pool to manage these objects;

React 17 has refactored the event system, and its changes:

20220524094816

  • The mounting mechanism of the event node is changed from document to root node, and this change will not cause Portals monitoring outside the root node to fail;
 import React from 'react';
import ReactDOM from 'react-dom';

class Foo extends React.Component {
  enter(e){ console.log('click foo');
  e.stopPropagation(); }
  render() {
    return <div style={{ height: 30, background: 'blue' }} onClick={this.enter}>Foo</div>;
  }
}

export default class Bar extends React.Component {
  enter(e){ console.log('click bar'); }
  componentDidMount() {
    ReactDOM.render(<Foo />, this.refs.c);
  }
  render() {
    return <div style={{ height: 50, background: 'red', color: 'white' }} onClick={this.enter}>Bar <div ref="c"/></div>;
  }
}

Looking at the above example, the page UI is as follows. If it was before 17, when we clicked on the Foo area, we expected the Bar area not to respond. Even if stopPropagation was added, it could not be prevented; but with the arrival of 17, this bug can be avoided. This is also to pave the way for 渐进式升级
20220528234609

  • Event callback timing is in sync with native events (this is really a big improvement);
  • SyntheticEvent is no longer stored in the event pool, so e.persit() will no longer take effect;

link up

v17 opens a new chapter in React's incremental upgrades (with a slight bluff)

17 onwards, allow different React versions on the same page. According to the official demo example, it is implemented based on the feature of lazy loading, and the usage is somewhat similar to the gameplay of SPA micro-applications. Personally, I don’t think this is black magic. If you don’t need to reload and expect a separate react version for a component, you should report an error or an error, like the following:
20220528181348

So by understanding the first two features, it really confirms the official sentence: 17 is only to pave the way for 18 and later versions, in order to make it easier for users to upgrade the version

React18 new features

Auto Bacthing

Batching is React's grouping of multiple state updates into a single re-render for better performance (less render times).
Before React 18, batched updates only happened in React event callbacks, and updates inside Promise, setTimeOut, native event callbacks, or any other events were not batched, for example 🌰:

 // 18以前: .
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // render 2次
}, 1000);

// 18及以后: 
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // render1次
}, 1000);

Bypassing Black Magic: flushSync

Custom rendering priority

When react16 exits asynchronous rendering, the concept of rendering priority is proposed, like: user input > animation > list display. When multiple rendering tasks arrive, it will render the high-priority task first.

But because this is an ideal idea, it is difficult for the program itself to judge what must be a high priority, because the user usage scenarios are too complicated; so in 18, this underlying capability was further opened, and several hooks were launched: startTransition, useTransition , useDeferredValue, etc. These hooks allow users to customize the rendering priority

For example, enter the search box, intuitively:
20220530095408

The following is the pseudo code, just watch the demo directly:

 import {startTransition} from 'react';
// 高优先级: 输入数据回显
setInputValue(input);

// 使用Transition 对低优先级的渲染进行标记
startTransition(() => {
  setQuery(input);
});

The official Liezi, I think it will be easier for users who are graphical. If you are interested, you can learn about it: <Official Example>

So the latest version of React divides state updates into two categories:

  • Urgent updates will act directly on user interactions such as typing, clicking, etc.
  • Transition updates transition the UI from one view to another

Through these hooks we can customize the rendering priority.

New entry mount API: createRoot

 // 18 以前:
import { render } from 'react-dom';
const container = document.getElementById('app');
render(<App tab="home" />, container);

// 18 以后:
import { createRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = createRoot(container); // 
root.render(<App tab="home" />);

It is worth mentioning that 18 is also compatible with the old mounting method, but this usage cannot use the new features (the development environment will prompt), which is also part of the incremental upgrade

11.55.29

incremental upgrade

The official word: Technically speaking, concurrent rendering is a breakthrough upgrade. Because concurrent rendering is interruptible, the component will behave slightly differently when it is enabled, about 0.2%.

Therefore, in order for everyone to upgrade to 18 more smoothly, the official proposed 渐进式升级 to provide a StrictMode API. Nodes wrapped with this module will comply with strict mode, which helps:

  • Identify insecure lifecycles
  • Warning for using obsolete string ref API
  • Warning for using the deprecated findDOMNode method
  • Detect unexpected side effects
  • Detect outdated context API
  • Ensure reusable state

The following demo, Header and Footer will be rendered in normal mode, while the Component node wrapped in StrictMode will be rendered in strict mode

 import React from 'react';

function ExampleApplication() {
  return (
    <div>
      <Header />
      <React.StrictMode>
        <div>
          <ComponentOne />
          <ComponentTwo />
        </div>
      </React.StrictMode>
      <Footer />
    </div>
  );
}

Strict mode cannot automatically detect the side effects of your application version upgrade, it can only help to find them and make them more deterministic by deliberately repeatedly calling some declared functions (please check the official documentation for details)

 // 正常模式
* React mounts the component.
  * Layout effects are created.
  * Effects are created.

// 严格模式
* React mounts the component.
    * Layout effects are created.
    * Effect effects are created.
* React simulates effects being destroyed on a mounted component.
    * Layout effects are destroyed.
    * Effects are destroyed.
* React simulates effects being re-created on a mounted component.
    * Layout effects are created
    * Effect setup code runs

Although this module is only valid in the development environment, careful people will find that repeated destruction and mounting will bring new problems, such as:

 const [value, setValue] = useState(0);
useEffect(() => {
  setValue(val => val + 1);
})
// 正常模式打印的是1,但严格模式这会打印2;

There have been articles discussing this issue in China, and there is also an issue in the react repository to discuss this issue. If you are interested, you can click here .

Analysis of concurrent rendering

First, before talking about react rendering, review a knowledge point: js execution and UI rendering in the browser occur sequentially in a thread (including js execution, event response, timer, UI rendering), and the execution of js is single-threaded (based on eventloop).

20220603155838

This single thread is decided, processing A cannot handle B.

With this consensus, let's take a look at the rendering history of react

Synchronized rendering

The earliest react (before 16) is synchronous, which means that when the user triggers an update through setState, and the update is rendered to the page, it will go through two processes:

  • Diff stage: the root node will start diff, and find the difference between the DOM tree before and after the update;
  • Commit stage: According to the result of diff, update the UI to the page;

Since the whole process is synchronous, it will always occupy the js thread; therefore, during an update process, interactive events such as clicks and inputs on the page will wait until the update is completed, which is obviously a bad experience.

Asynchronous rendering

In order to solve the problem of synchronous rendering blocking the main thread, then make rendering more flexible - the biggest problem is not performance, but scheduling (React Conf 2018).

Based on the birth of a sensational term in the front-end circle Fiber , the biggest feature of the new rendering architecture is that it divides the previous one-way-to-black gameplay into two stages:

  • render phase: a task chain with a linked list structure, which can be interrupted;
  • Commit stage: is the process of updating the UI to the interface, which is synchronous and uninterrupted;

The relationship between the nodes in the render stage is represented by the linked list, and the method of time slicing is added. Whether the nodes on the linked list continue to compare backwards depends on whether the current thread is idle; and react will mark each update task with a priority, if the new If the update priority is higher than the task being processed, the previous task will be interrupted and discarded to process the higher priority task;

What needs to be understood here is that once an update task is interrupted and discarded, after the high-priority task is executed, the task needs to be calculated again from scratch.

Another point to remember is that there are Fibers and then hooks, not hooks that bring Fibers.

Concurrent rendering

As long as you have read some articles on React18, you may have heard of Concurrent Mode, Concurrent React or Concurrent features, these terms are not important, the important thing is to understand his purpose.

First of all, let's correct a wrong assumption that everyone may hear about asynchronous rendering: asynchronous rendering does not mean that two or more branches of a tree are rendered at the same time.

Move your toes and think about it, how is this possible, which itself is contrary to the principle of browser rendering.

Official original words:

Concurrency is not a feature, per se. It's a new behind-the-scenes mechanism that enables React to prepare multiple versions of your UI at the same time.

multiple versions of your UI circle it, the exam is to be taken.

Concurrent rendering successfully solves the problem of interruption and abandonment in asynchronous rendering, which can be resumed after interruption; however, in some scenarios, there will also be a problem of interruption and abandonment.

This ability can also unlock another usage scenario in the future: state reuse. For example, a tab switch, when switching from a to b, and then switching back to a from b, at this time, through some implementations, we can reuse the state and quickly display a on the screen;

The significance of concurrent rendering is far more than this (including the server and native side), I only picked up a few points that I can understand and share with you. Anyway, the official writing is very good, I personally still look forward to it.

Recommended reading:

Summarize

Through the familiarity with the new features of react18 and the explanation of the rendering mode, we can feel that this version will bring a visible improvement to the experience of our application, provided that you do not abuse it and use it.

And with the continuous exposure based on the bottom layer and the continuous construction of the concurrent mode, we may not use react, but Remix, Next, an ecological framework based on the react library, which is also the meaning of the establishment of the React working group. One, better build the React ecosystem.

It's hard to imagine that this is actually my first article in 2022. The most confusing thing in China this year is the Chinese economy, the second may be me, I hope this is a turning point! ! !

20220603161837


前端黑洞
3.5k 声望4.7k 粉丝

不要假装很努力,因为结果不会陪你演戏