在同构 React Web 应用程序中有选择地进行服务器渲染的最佳方式是什么?

What is the best way to selectively server-render in an isomorphic React web app?

我想要包含大量内容的网页的最佳性能。特别感兴趣的是,在移动设备上,我希望用户尽快看到首屏内容,然后尽快让应用程序 bootstrap。

我有一个变量 isBrowser,它在浏览器环境中是 true,但在服务器环境中是 false。考虑以下渲染函数:

render() {
  return (
    <div>
      <ContentAboveTheFold />
      { isBrowser && <ContentBelowTheFold /> }
    </div>
  )
}

请注意,通过以这种方式构建 render(),服务器要呈现的标记更少,通过网络传输的数据更少,浏览器在第一次通过时呈现的标记也更少。

这工作正常,但在控制台中 React 警告

React attempted to use reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server.

在服务器上,React 渲染标记时将校验和作为属性嵌入到顶级元素中(例如 data-react-checksum="941190765")。然后在客户端,React 在第一次渲染后计算校验和,如果它与服务器的校验和不同,它会完全丢弃服务器生成的标记并用客户端生成的标记替换它。

作为一种解决方法,我发现在我的顶级组件的 componentDidMount 生命周期方法中,我可以在下一个动画帧上安排以下操作:

componentDidMount() {
  requestAnimationFrame(() => {
    appIsMounted = true;
    this.forceUpdate();
  });
}

然后我可以像这样编写渲染方法并且 React 不会生成任何关于校验和的警告:

render() {
  return (
    <div>
      <ContentAboveTheFold />
      { appIsMounted && <ContentBelowTheFold /> }
    </div>
  )
}

这样做有什么明显的性能优势吗?在任何一种情况下,首屏的内容都会同样快速地出现,对吧?额外的复杂性是否合理?

是的,用 requestAnimationFrame/setTimeout 更新是正确的方法。

不过,我会将其置于状态,而不是使用变量和 forceUpdate。