What does React 18 bring

I concluded that Act18 included three major changes

  1. Automatic batching, or automatic batching to reduce rendering.
  2. New function startTransition.
  3. New SSR architecture.

This is possible thanks to the addition of Concurrent rendering, or concurrent rendering, to React18. This mechanism happens mostly behind the scenes, but it unlocks a lot of new possibilities for React to help you improve the real and perceived performance of your application. Also, the React team took an incremental upgrade approach, meaning that concurrent rendering was used only for new feature updates. This means you don’t have to rewrite code to use React 18 directly, and you can try out new features at your own pace and needs, which is developer-friendly.

Automatic batch processing

Batch processing is grouping react updates into a single re-render for better performance, as in the example below, React only performs a render once

export function Demo1(){ const [count1, setCount1] = useState(1); const [count2, setCount2] = useState(2); const handleClick = useCallback(() => { setCount1(c => c + 1); // No rerender setCount2(c => c + 2); // React batch}, []); return ( <div> <h1>{count1}</h1> <h2>{count2}</h2> <button onClick={handleClick}>Click</button> </div> ); };Copy the code

This is useful for performance because it avoids unnecessary re-rendering. It also prevents the component from presenting a “half-finished” state that updates only one state variable, which can lead to errors. However, React batch update times are inconsistent. For example, if you need to fetch data and then update the state, React does not batch, but instead performs two separate updates. This is because React used to only batch update during browser events (such as clicks), but here we update the state after the event has already been processed (in the FETCH callback)

export function Demo1(){ const [count1, setCount1] = useState(1); const [count2, setCount2] = useState(2); const handleClick = useCallback(() => { fetch(url).then(res => { setCount1(c => c + 1); setCount2(c => c + 2); }}), []); return ( <div> <h1>{count1}</h1> <h2>{count2}</h2> <button onClick={handleClick}>Click</button> </div> ); };Copy the code

Prior to React 18, we only made batch updates during React event handlers. By default, updates in Promises, setTimeout, native event handlers, or any other event are not batched in React.

So what is automatic batching

Starting with React 18, React starts with createRoot, and updates anywhere are automatically batched, meaning that updates within any event will be batched in the same way as updates within react events. Results in less rendering work, resulting in better performance in your application:

fetch(url).then(res => {
    setCount1(c => c + 1);
    setCount2(c => c + 2);
});
setTimeout(() => {
    setCount1(c => c + 1);
    setCount2(c => c + 2);
}, 2000);
Copy the code

As mentioned above, act18 does automatic batching, so how do you turn this new feature off? In general, batching is safe, but some code may rely on reading something from the DOM immediately after a state change, in which case the batching is disabled through reactdom.flushsync ().

   setTimeout(() => {
      flushSync(() => {
        setCount1(c => c + 1);
      });
      flushSync(() => {
        setCount2(c => c + 2);
      });
    }, 2000);
Copy the code

New features startTransition

Official overview: With React 18, we introduced a new API that helps keep your applications responsive even during big-screen updates. This new API lets you significantly improve user interaction by marking specific updates as “transformations.” React will let you provide visual feedback during state transitions and keep the browser responsive when transitions occur.

What problem does that solve?

For example, we now have such a demand, Input in the Input Input box, we get the new value to search and update the list, and if the list content is too much, there was a delay may lead to a page in the render content, this is, when we are in the Input box type interaction can appear caton, interactive feel slow and unresponsive, even if the list is not too long, But the list items themselves can be complex, different with each keystroke, and there may be no clear way to optimize their rendering.

That conceptually requires two updates, one for the input field, but one for the list. By comparison, the update of the input box is obviously a more urgent matter. Users expect the first update to be immediate because the native browser for these interactions is fast. But the second update may be a bit delayed. Users don’t want it to complete immediately. (In fact, we often use techniques such as dejitter to update.)

/ / emergency setInputValue (input); // Not urgent setSearchQuery(input);Copy the code

Before React 18, all updates were rendered urgently. This means that the two states above will still be present at the same time, and will still prevent the user from seeing feedback on their interaction until everything is present. What’s missing is a way to tell React which updates are urgent and which aren’t.

How does startTransition help?

The new API is able to flag this update.

import { startTransition } from 'react'; setInputValue(input); // Urgent startTransition(() => {// not very urgent setSearchQuery(input); });Copy the code

The update startTransition wrapped in it is treated as non-urgent and is interrupted if a more urgent update (such as a click or keystroke) occurs. If the user interrupts the conversion, React will throw out the old unfinished render work and render only the latest updates.

How is it different from setTimeout?

setInputValue(input);

setTimeout(() => {
  setSearchQuery(input);
}, 0);

Copy the code

This will delay the second update until after the first update is rendered. Throttling and jitter removal are common variations of this technique.

One important difference is that startTransition is not scheduled later like setTimeout. It executes immediately. The function passed to startTransition runs synchronously, but any updates within it are marked as “Transitions.” React will use this information later when it processes updates to determine how to render them.

Another important difference is that large screen updates in setTimeout still lock the page after the timeout. If the user is still typing or interacting with the page when the timeout is triggered, they will still be prevented from interacting with the page. But status updates labeled startTransition are interruptible, so the page is not locked. They allow browsers to process events in small gaps between rendering different components. If user input changes, React doesn’t have to continue rendering content that the user is no longer interested in.

Finally, because setTimeout only delays updates, displaying load indicators requires writing asynchronous code, which is often vulnerable. With transformations, React keeps track of pending status for you, updates based on the current state of the transformation, and enables you to display user load feedback while the user is waiting.

Pending state during the transition.

import { useTransition } from 'react';

const [isPending, startTransition] = useTransition();

{isPending && <Loading />}
Copy the code

Where to use it?

You can use startTransition to wrap any updates you want to move into the background. In general, these types of updates fall into two categories:

Slow rendering: Updates take time and React requires a lot of work to convert the UI to display results.

Slow network: These updates take time because React is waiting for some data from the network. This use case is tightly integrated with suspense.

SSR for Suspense

SR for Suspense solves three main problems:

  • You no longer need to wait for all the data to load on the server before sending the HTML. Instead, when you have enough content to display the application’s shell, you start sending the HTML immediately and stream the rest of the HTML when you’re ready.
  • You no longer need to wait for all JavaScript to load before you can start hydrating. Instead, you can split the code for use with server rendering. The server HTML will be preserved and React will hydrate it when the relevant code loads.
  • You no longer need to wait for all components to start interacting with the page. Instead, you can rely on Selective Chocolate to prioritize the components that users interact with and moisturize them early on.

In Server Render of React 18, you can solve the above three problems by using pipeToNodeWritable instead of renderToString and working with Suspense.

The biggest difference is that server-side rendering is changed from simple res.send to res.socket, which changes rendering from a single action to a persistent action. How does react 18 SSR work? To sum up the key point is’ on demand ‘.

  1. be<Suspense>Wrapped blocks that do not block the first swallow when rendered on the server and are hit in real time after the block is ready (including asynchronous fetch) to the page (in HTML mode, at this point without hydration)fallbackThe content of the.
  2. Hydration is also gradual, so that the page doesn’t get stuck implementing all the full jS at once (after all, it’s just a few callback registrations in React, Hooks of sorts, a huge amount of apps).
  3. After being split into several variations, React also monitors mouse clicks in advance, prioritization of click regions, and even preempts ongoing variations of Chocolate in other regions.