Writing in the front

The React SSR API is split into two parts, one is server-side (React-DOM /server) and the other is still client-side (React-DOM).

A ReactDOMServer.

The ReactDOMServer API renders the React component as static (HTML) tags on the server side:

The ReactDOMServer object enables you to render components to static markup.

Rendering the component tree to the corresponding HTML tag can also be done in the browser environment, so the server-side React DOM API is divided into two categories:

  • String apis that run across Node.js and browser environments: renderToString(), renderToStaticMarkup()

  • RenderToNodeStream (), renderToStaticNodeStream()

renderToString

ReactDOMServer.renderToString(element)
Copy the code

For the most basic SSR API, type the React component (ReactElement, to be exact) and output the HTML string. The client Hydrate API then attaches interaction to the view structure returned by the server to complete the page rendering:

If you call ReactDOM.hydrate() on a node that already has this server-rendered markup, React will preserve it and only attach event handlers.

renderToStaticMarkup

ReactDOMServer.renderToStaticMarkup(element)
Copy the code

RenderToStaticMarkup is similar to renderToString, except that in API design, renderToStaticMarkup is only used for scenarios with pure presentation (no event interactions, no hydrate required) :

This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save some bytes. If you plan to use React on the client to make the markup interactive, do not use this method. Instead, use renderToString on the server and ReactDOM.hydrate() on the client.

Thus the renderToStaticMarkup only generates clean HTML with no additional DOM attributes (such as data-reactroot), giving a slight advantage in response size

Before React 16, SSR used the string checksum based HTML node reuse method. The consistency of word to word was strictly checked. If a mismatch was found, the server rendering result was discarded completely and the client rendered again:

If for any reason there’s a mismatch, React raises a warning in development mode and replaces the entire tree of server-generated markup with HTML that has been generated on the client.

A number of additional attributes are generated:

// renderToString <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>Copy the code

RenderToStaticMarkup also has the benefit of generating clean, clean HTML:

// renderToStaticMarkup
<div data-reactroot="">
  This is some <span>server-generated</span> <span>HTML.</span>
</div>
Copy the code

React 16 uses single-node validation to reuse HTML nodes (returned by the server). Data-reactid and data-react-checksum are not generated, and the volume difference between the two apis becomes very small. For example, for the React component:

class MyComponent extends React.Component { state = { title: 'Welcome to React SSR! '}; } render() { return ( <div> <h1 className="here"> {this.state.title} Hello There! </h1> </div> ); }}Copy the code

The rendering results are as follows:

// renderToString <div data-reactroot=""><h1 class="here">Welcome to React SSR! <! -- --> Hello There! </h1></div> // renderToStaticMarkup <div><h1 class="here">Welcome to React SSR! Hello There! </h1></div>Copy the code

React 17.0.1. RenderToStaticMarkup is different from renderToString.

  • RenderToStaticMarkup does not generate data-reactroot

  • RenderToStaticMarkup does not generate
    (equivalent to merging text nodes, node reuse is not considered, which is an additional optimization measure for static rendering)

renderToNodeStream

ReactDOMServer.renderToNodeStream(element)
Copy the code

The Stream API corresponding to renderToString returns the HTML string generated by renderToString as a Node.js Readable Stream

P.S. returns a byte stream encoded in UTF-8 by default

P.S. The implementation of this API relies on the Stream feature of Node.js, so it cannot be used in a browser environment

renderToStaticNodeStream

ReactDOMServer.renderToStaticNodeStream(element)
Copy the code

The Stream API corresponding to renderToStaticMarkup returns the clean HTML string generated by renderToStaticMarkup as a Node.js Readable Stream

P.S. is also utF-8 encoded and cannot be used in a browser environment

2. ReactDOM

hydrate()

ReactDOM.hydrate(element, container[, callback])
Copy the code

Exactly the same as the render() function signature:

ReactDOM.render(element, container[, callback])
Copy the code

Hydrate () is used with SSR and differs from Render () in that it is possible to reuse existing HTML nodes returned by the server during the render process and only attach interaction (event listening, etc.) to them without recreating DOM nodes:

React will attempt to attach event listeners to the existing markup.

Note that when the HTML returned by the server is inconsistent with the client render result, the HYDRATE () does not correct the SSR render result except for the text node for performance reasons, but simply goes wrong:

There are no guarantees that attribute differences will be patched up in case of mismatches. This is important for performance reasons because in most apps, mismatches are rare, and so validating all markup would be prohibitively expensive.

These inconsistencies are reported as warnings only in development mode, so SSR hydrationwarnings must be addressed as errors:

This performance optimization means that you will need to make extra sure that you fix any markup mismatch warnings you see in your app in development mode.

Specifically, for expected inconsistencies, such as time stamp, the element’s HydrationWarning can be explicitly ignored with the suppressHydrationWarning={true} attribute (the warning is ignored, not corrected, so the server rendering results are retained). If you have to render different content on the server side and the client side, it is recommended to ensure that the first render content is the same, and then update it (of course, the performance will be a little worse), for example:

class MyComponent extends React.Component { state = { isClient: false } render() { return this.state.isClient ? 'rendering... Client content ':' Render... Server content '; } componentDidMount() { this.setState({ isClient: true }); }}Copy the code

3.SSR related API restrictions

Most lifecycle functions are not executed on the server side

In SSR mode, the server only performs three life cycle functions:

  • constructor
  • getDerivedStateFromProps
  • render

None of the rest of the lifecycle is executed on the server side, including the getDerivedStateFromError, componentDidCatch, and other error handling apis

P.S. Deprecated componentWillMount and UNSAFE_componentWillMount are mutually exclusive with getDerivedStateFromProps and getSnapshotBeforeUpdate. If either of the latter new apis exists, the first two old apis will not be called

Error Boundary and Portal are not supported

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.

In order to support streaming rendering and maintain consistency between the String API and Stream API output, two features that cause backtracking are sacrificed:

  • Error Boundary: Catches run-time errors of descendant components and renders a degraded UI

  • Portal: The ability to render components to any DOM node specified while keeping events bubbling at the component level

It is easy to understand that streaming rendering in response cannot (backtrack) modify what has been sent, so other similar scenarios are not supported, such as dynamically inserting a style or script tag into the head during rendering

P.S. for more discussion of SSR Error Boundary, see componentDidCatch Doesn’t work in React 16’s renderToString

The resources

  • ReactDOMServer
  • ReactDOM
  • The Component Lifecycle
  • What’s New With Server-Side Rendering in React 16
  • react lifecycle methods diagram

It is good to have gained and confused

Follow the “front end back” wechat official account and you will receive a series of “heart original” high-quality technical articles on topics including but not limited to front-end, Node.js and server-side technologies

This article was originally published on ayqy.net. The original link is www.ayqy.net/blog/react-…