Skip to main content

React 16

Free2017-12-31#JS#React 16 killer feature#React 16 features#React async rendering#react异步渲染#react增量渲染

Let's see if this big move, two years in the making, has brought any killer features?

I. Features

fragment

Templates support fragment and string types, corresponding to ReactElement arrays and strings.

v16.2.0 also introduced JSX fragment support: <></>

error boundary

Component-level error handling, supporting the capture of exceptions within the child component tree, serving as a fallback solution for the UI layer.

portal

Allows the component tree structure to differ from the DOM tree structure, used for scenarios like hovercards and tooltips.

For example, in terms of DOM structure, a target and its tooltip are generally siblings (for layout needs), but logically the tooltip belongs to the target, forming a parent-child relationship. The portals feature is designed to handle such scenarios.

Specifically, event bubbling is handled such that the parent component of a portals component can still receive bubbling notifications (React had a built-in event system to smooth out DOM event bubbling differences before version 16, and here it conveniently supports bubbling around corners Example).

support for custom DOM attributes

Previously, a whitelist of HTML/SVG attribute names was built-in, and custom attributes would be intercepted and ignored. React 16 has removed this restriction.

There are two reasons for removing this restriction: first, this layer of built-in attribute filtering was very unfriendly to non-standard new attributes (such as those in the proposal stage) and other libraries/frameworks (like Angular and Polymer); second, a non-trivial attribute whitelist had to be included in the bundle, which was quite a hassle to maintain.

improved server-side rendering

Claimed to be 3 times faster than React 15 (in benchmark scenarios; reportedly 1.3 times in certain business scenarios), achieved through several changes:

  • Stream support

  • Removed redundant process.env access at build time (accessing this variable in a Node environment is time-consuming).

  • The client no longer calculates checksums; instead, it reuses existing DOM as much as possible (similar to Inferno, which thoroughly implements DOM node reuse, though Inferno's reuse reportedly faced some issues and is now offered as an option rather than a highlight feature).

Note: React 16 also seems to have some issues with DOM node reuse:

However, it’s dangerous to have missing nodes on the server render as this might cause sibling nodes to be created with incorrect attributes.

P.S. The official team may provide a dedicated blog post later regarding which specific dangerous scenarios to watch out for; it hasn't been clarified yet.

reduced file size

React bundle slimming (refactoring, flattened packaging strategy, and switching to Rollup), reducing the size by 30%.

II. SSR

The biggest change is likely in SSR, which has been seriously implemented this time (previous SSR implementations felt like an afterthought).

1. New APIs

On the server side, renderToNodeStream and renderToStaticNodeStream have been added, corresponding to renderToString and renderToStaticMarkup respectively.

On the client side, hydrate has been added.

2. Relaxed Consistency Checks

Client-side validation is no longer as strict:

  • In React 15, the client would perform character-level consistency checks on the SSR results; any mismatch would trigger the client to regenerate and replace everything.

  • React 16 allows for inconsistent attribute order, does not automatically fix inconsistent attributes, and performs subtree-level modifications when encountering mismatched tag structures, rather than replacing everything.

Additionally, checksums (data-react-checksum) and IDs (data-reactid) on the Server HTML structure have been removed, significantly reducing the response body size:

<!-- react 15 -->
<div data-reactroot="" data-reactid="1"
    data-react-checksum="122239856">
  <!-- react-text: 2 -->This is some <!-- /react-text -->
  <span data-reactid="3">server-generated</span>
  <!-- react-text: 4--> <!-- /react-text -->
  <span data-reactid="5">HTML.</span>
</div>

<!-- react 16 -->
<div data-reactroot="">
  This is some <span>server-generated</span> <span>HTML.</span>
</div>

3. Performance Optimization

Redundant process.env.NODE_ENV access is removed by default, eliminating the need for manual compilation to remove it.

SSR no longer creates one-off virtual DOMs, making the whole process much faster.

Support for streaming brings the following performance benefits:

  • The server generates and sends content simultaneously instead of waiting for SSR to complete before sending everything at once, resulting in a faster TTFB (time to first byte).

  • The client receives and renders content simultaneously instead of waiting for the full response, moving up the timeline for parsing, rendering, and loading external resources.

4. Error Boundary and Portal are Not Supported

React 16 SSR does not support Error Boundary or Portal.

Errors during server-side child component rendering will not be caught by an Error Boundary. Error Boundary was sacrificed for the performance benefits of streaming:

This is intentional / a known limitation. With streaming rendering it's impossible to "call back" markup that has already been sent, and we opted to keep renderToString and renderToNodeStream's output identical.

Neither renderToNodeStream/renderToStaticNodeStream nor renderToString support Error Boundaries. As mentioned, two separate mechanisms were not maintained to keep the output consistent.

P.S. For more information on SSR Error Boundaries, please see componentDidCatch doesn't work in React 16's renderToString.

The Portal feature can cause "reflow," which follows the same principle as Error Boundaries and cannot be supported under the streaming mechanism (it is impossible to insert Portal content into a stream that has already been sent).

III. Fiber

A brand new core architecture (two years in the making) that completely rewrote the component rendering mechanism. The most critical feature is async rendering, enabling schedulable rendering (completely solving the problem where the mount process cannot be interrupted once started).

Refactoring Process

The execution process of such a massive, structural refactoring is quite interesting. Simply put:

  • Instead of creating a new branch, it was switched via the useFiber feature toggle, reportedly to simplify daily maintenance and conflict resolution.

  • Step one was to build a skeleton. It supported some APIs, and then all test cases were gradually passed (so-called TDD, Test-Driven Development, eventually reaching 2,000 cases).

  • Engineering auxiliary means. These included progress tracking, tracking unit test results (making it easy to see what a commit fixed or broke; the method was simple: adding tests-failing.txt and tests-passing.txt to Git tracking), and continuous production environment verification (so-called dogfooding; the entire process from the early stages to the final unit test passing was constantly validated through 'real-world' tests, a form of tangible conviction).

  • Finding suitable business cases as a testbed. Once it was relatively stable, actual business cases were used to prove it was ready for production. Data was gathered through A/B testing, letting 200 million users help experience it before switching to full rollout. Simultaneously, internal systems were fully switched to expand verification scenarios, and finally, a grayscale rollout was performed for React Native applications.

  • The new mechanism was not directly deployed. For now, it still executes synchronously (although Fiber supports asynchronous mode), with plans to wait a few more months for a smooth transition.

P.S. For details on the refactoring process, see React 16: A look inside an API-compatible rewrite of our frontend UI library.

Therefore, async rendering is not supported for now:

This initial React 16.0 release is mostly focused on compatibility with existing apps. It does not enable asynchronous rendering yet. We will introduce an opt-in to the async mode later during React 16.x. We don't expect React 16.0 to make your apps significantly faster or slower, but we'd love to know if you see improvements or regressions.

Advantages

  • New Features

    Features that were previously difficult to implement, such as component-level error handling and render returning multiple components, can now be created after the refactoring.

  • Experience Advantages

    Fiber is not necessarily faster, but it is smoother (splitting rendering tasks and balancing scheduling to avoid occupying the main thread for long periods). Additionally, it features task priority control, allowing animations and the like to be executed first.

    The difference is quite obvious; see React Stack vs Fiber.

References

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment