B station synchronous video tutorial

resources

  1. React18 plan

  2. React 18 discussion board

  3. React 18: Automatic batching for fewer renders in React 18

  4. Suspense for SSR Architecture in React18

  5. Suspense of React18 is Behavioral Changes to Suspense in Suspense

  6. startTransition

The body of the

React 18 Alpha has been released.

As a preliminary preview of the Alpha version of Act18, most of the new features have been finalized, but some work remains to be done.

What will React 18 bring

After the release of Act18, the following changes are expected:

  1. Improve existing attributes, such as automatic batching, making SSR support for Suspense and Lazy, improving Suspense, etc.
  2. Support Concurrent mode, bringing new apis such as startTransition, useDeferredValue, etc.

To support these features, Act18 adds not only multitasking, but also priority-based rendering, scheduling, and interrupting.

React18 added the optional “Concurrent rendering” mode, which allows React to support multiple UI versions at the same time. The change is largely invisible to developers, but it unlocks a number of new features in the React app for improved performance.

Finally, don’t worry, we can use Act18 without rewriting the code.

The trial React18 Alpha

Create an

npx create-react-app react18-ice
cd react18-ice
yarn add react@alpha react-dom@alpha
yarn start
Copy the code

The SRC/index. Js

ReactDOM.render(<App/>.document.getElementById("root"));
Copy the code

Switch to

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
Copy the code

Concurrent mode

Concurrent mode is a new set of React features that help applications stay responsive and adjust appropriately to the user’s device performance and network speed.

In Concurrent mode, React can update multiple states at the same time — just as branching allows different team members to work independently:

  • For CPU-bound updates (such as creating new DOM nodes and running code in components), concurrency means that a more urgent update can “break” a rendering that has already started.
  • For io-bound updates (such as loading code or data from the network), concurrency means React can start rendering in memory even before all the data arrives, then skip the unpleasant blank load state.

The important thing is that you use React in the same way. Components, props, and state all work in the same basic way. When you want to update the screen, set state.

React uses a heuristic to determine the “urgency” of updates and allows you to tweak it with a few lines of code so that you can achieve the desired user experience with each interaction.

In simple terms, what Concurrent mode wants to do is that the user can customize the priority of the update task and be notified to React, which then processes the update task of different priorities. Of course, high-priority tasks are processed first, and low-priority tasks can be interrupted.

Concurrent mode reduces the need for buffeting and throttling in the UI. Because rendering can be broken, React does not need to artificially delay work to avoid stalling (such as using setTimeout). It can start rendering immediately, but interrupts this work when it is necessary to keep the application responsive.

Suspense

Used for data acquisition. Zh-hans.reactjs.org/docs/concur…

You can “wait” for the object code to load, and you can directly specify a load interface (like a spinner) to display while the user is waiting.

import {useState, Suspense} from "react";
import User from ".. /components/User";
import Num from ".. /components/Num";
import {fetchData} from ".. /utils";
import ErrorBoundaryPage from "./ErrorBoundaryPage";

const initialResource = fetchData();

export default function SuspensePage(props) {
  const [resource, setResource] = useState(initialResource);

  return (
    <div>
      <h3>SuspensePage</h3>
      <ErrorBoundaryPage fallback={<h1>Network error</h1>} ><Suspense fallback={<h1>loading - user</h1>} ><User resource={resource} />
        </Suspense>
      </ErrorBoundaryPage>

      <Suspense fallback={<h1>loading-num</h1>} ><Num resource={resource} />
      </Suspense>

      <button onClick={()= > setResource(fetchData())}>refresh</button>
    </div>
  );
}
Copy the code
Error handling

Promises: Every time we use Promises, we will most likely use Catch () to make mistakes. But when we use Suspense, we don’t wait for Promises to start rendering, so catch() doesn’t apply. What about error handling in this case?

In Suspense, errors thrown when fetching data are handled in the same way as errors reported in component rendering — you can render an error bound component at the desired level to “catch” all error messages below.

export default class ErrorBoundaryPage extends React.Component {
  state = {hasError: false.error: null};
  static getDerivedStateFromError(error) {
    return {
      hasError: true,
      error,
    };
  }
  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }
    return this.props.children; }}Copy the code

SuspenseList

Use to control the display order of Suspense components.

revealOrderSuspense loading order

All Suspense is shown together, which means that you don’t show all things together until the last one is loaded

Forward displays Suspense in order

Work backwards to show Suspense

tailWhether to show fallbacks is only valid for revealOrder for forwards or backwards

Hidden don’t show

Collapsed reveals itself again

import {useState, Suspense, SuspenseList} from "react";
import User from ".. /components/User";
import Num from ".. /components/Num";
import {fetchData} from ".. /utils";
import ErrorBoundaryPage from "./ErrorBoundaryPage";

const initialResource = fetchData();

export default function SuspenseListPage(props) {
  const [resource, setResource] = useState(initialResource);

  return (
    <div>
      <h3>SuspenseListPage</h3>
      <SuspenseList tail="collapsed">
        <ErrorBoundaryPage fallback={<h1>Network error</h1>} ><Suspense fallback={<h1>loading - user</h1>} ><User resource={resource} />
          </Suspense>
        </ErrorBoundaryPage>

        <Suspense fallback={<h1>loading-num</h1>} ><Num resource={resource} />
        </Suspense>
      </SuspenseList>

      <button onClick={()= > setResource(fetchData())}>refresh</button>
    </div>
  );
}
Copy the code

startTransition

** Uses: ** marks an update as Transition.

The update function in the startTransition package is treated as a non-emergency event, and the startTransition package will be interrupted if other urgent updates come in.

transition

React divides status updates into two types:

  • Urgent Updates refers to direct interactions. Such as clicking, typing, scrolling, dragging and so on
  • Transition updates, such as UI updates from one view to another

Double buffering – Baidu Encyclopedia

When we watch TV, the screen we see is called the OSD layer, that is, we can only see the image displayed on the OSD layer. Now I need to create a virtual, invisible OSD layer on which I can draw pictures (such as dots and lines), which I call offScreen (background buffer). So this offscreen is in memory, and we’re drawing on it, and the stuff on this offscreen can be displayed on the OSD layer, and we need a function to create this offscreen, Return the handle to the offScreen (integer pointer), width, height, and pointer to the new offScreen buffer created outside the function. This buffer is the height width of offScreen and the size of each pixel of offScreen data. Flicker is a common problem in graphics programming. Graphical operations that require multiple complex drawing operations can cause rendered images to flicker or otherwise have an unacceptable appearance. The use of double buffering solves these problems. Double buffering uses memory buffers to solve flicker problems caused by multiple draw operations. When double buffering is enabled, all drawing operations are rendered to the memory buffer first, not the drawing surface on the screen. After all drawing operations are complete, the memory buffer is copied directly to the drawing surface associated with it. Because only one graphical operation is performed on the screen, image flicker caused by complex drawing operations is eliminated.

Usage:

import {useEffect, useState, Suspense} from "react";
import Button from ".. /components/Button";
import User from ".. /components/User";
import Num from ".. /components/Num";
import {fetchData} from ".. /utils";

const initialResource = fetchData();

export default function TransitionPage(props) {
  const [resource, setResource] = useState(initialResource);

  // useEffect(() => {
  // console.log("resource", resource); //sy-log
  // }, [resource]);

  return (
    <div>
      <h3>TransitionPage</h3>
      <Suspense fallback={<h1>loading - user</h1>} ><User resource={resource} />
      </Suspense>

      <Suspense fallback={<h1>loading-num</h1>} ><Num resource={resource} />
      </Suspense>

      <Button
        refresh={()= >{ setResource(fetchData()); }} / ></div>
  );
}
Copy the code

Button

import {
  //startTransition,
  useTransition,
} from "react";

export default function Button({refresh}) {
  const [isPending, startTransition] = useTransition();

  return (
    <div className="border">
      <h3>Button</h3>
      <button
        onClick={()= >{ startTransition(() => { refresh(); }); }} disabled={isPending}> Click to refresh data</button>
      {isPending ? <div>loading...</div> : null}
    </div>
  );
}
Copy the code
And the similarities and differences between setTimeout

Before startTransition, we can use setTimeout for optimization. However, setTimeout can be discarded with startTransition when dealing with the above optimization. There are three main reasons:

First, unlike setTimeout, startTransition does not delay scheduling but executes immediately. StartTransition receives functions that execute synchronously, except that the update is marked with a “Transitions”. This tag is used as a reference when React processes updates internally. This means that passing an Update to startTransition can be handled earlier than setTimeout. On faster devices, the transition is invisible to the user.

Usage scenarios

StartTransition can be used any time you want to update. But practically speaking, here are two typical scenarios:

  • Render slow: If you have a lot of less urgent content to render and update.

  • Slow network: If your updates take a lot of time to get from the server. Suspense can also be used at this time.

useTransition

You can use the React hook API useTransition to update the startTransition status.

import { useTransition } from 'react';
const [isPending, startTransition] = useTransition();
Copy the code

IsPending is true if transition is incomplete, false otherwise.

The source code interpretation

useDeferredValue

It allows us to delay updating some of the less important parts.

Equivalent to Transitions for the parametric version.

For example: The following diagram, when the user input in the input box “book”, the user should immediately see the reaction of the input box, by contrast, the fuzzy query box below if delayed is perfectly acceptable, for a while because the user may continue to modify the input box content, in the process of the fuzzy query results will change, But this change is less important to the user, who is most interested in seeing the final match.

Usage:

import {useDeferredValue, useState} from "react";
import MySlowList from ".. /components/MySlowList";

export default function UseDeferredValuePage(props) {
  const [text, setText] = useState("hello");
  const deferredText = useDeferredValue(text);

  const handleChange = (e) = > {
    setText(e.target.value);
  };
  return (
    <div>
      <h3>UseDeferredValuePage</h3>{/* Keep passing the current text to input */}<input value={text} onChange={handleChange} />{/* But you can "postpone" the list if necessary */}<p>{deferredText}</p>

      <MySlowList text={deferredText} />
    </div>
  );
}
Copy the code

MySlowList

import React, {memo} from "react";

function ListItem({children}) {
  let now = performance.now();
  while (performance.now() - now < 3) {}
  return <div className="ListItem">{children}</div>;
}

export default memo(function MySlowList({text}) {
  let items = [];
  for (let i = 0; i < 80; i++) {
    items.push(
      <ListItem key={i}>
        Result #{i} for "{text}"
      </ListItem>
    );
  }
  return (
    <div className="border">
      <p>
        <b>Results for "{text}":</b>
      </p>
      <ul className="List">{items}</ul>
    </div>
  );
});
Copy the code
The source code interpretation