如何在React.js中解析FOUC [英] How to resolve FOUC in React.js

查看:130
本文介绍了如何在React.js中解析FOUC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经从create-react-app构建了react.js网站. 但是在生产模式下,存在FOUC,因为样式是在呈现html之后加载的.

I have built react.js site from create-react-app. But in production mode, there is FOUC because styles are loaded after html is rendered.

有什么办法解决这个问题?我一直在Google搜索答案,但还没有找到合适的答案.

Is there any way to resolve this? I have been searching google for answers, but haven't found proper one yet.

推荐答案

FOUC

FOUC-所谓的无样式内容闪烁可能与解决该问题的许多尝试一样有问题.

FOUC

FOUC - so called Flash of Unstyled Content can be as very problematic as so many tries of solving this issue.

让我们考虑以下路由配置(反应路由器):

Let's consider following configuration of routing (react-router):

...
<PageLayout>
  <Switch>
    <Route exact path='/' component={Home} />
    <Route exact path='/example' component={Example} />
  <Switch>
</PageLayout>
...

其中PageLayout是一个简单的 hoc ,其中包含div包装器, page-layout类并返回它的孩子.

where PageLayout is a simple hoc, containing div wrapper with page-layout class and returning it's children.

现在,让我们集中讨论基于路线的组件渲染.通常,您将React Compoment用作component道具.但是在我们的案例中,我们需要动态获取它,以应用有助于避免FOUC的功能.因此我们的代码将如下所示:

Now, let's focus on the component rendering based on route. Usually you would use as component prop a React Compoment. But in our case we need to get it dynamically, to apply feature which helps us to avoid FOUC. So our code will look like this:

import asyncRoute from './asyncRoute'

const Home = asyncRoute(() => import('./Home'))
const Example = asyncRoute(() => import('./Example'))

...

<PageLayout>
  <Switch>
    <Route exact path='/' component={Home} />
    <Route exact path='/example' component={Example} />
  <Switch>
</PageLayout>

...

为澄清起见,我们还展示asyncRoute.js模块的外观:

to clarify let's also show how asyncRoute.js module looks like:

import React, { Component } from 'react'
import PropTypes from 'prop-types'

import Loader from 'components/Loader'

class AsyncImport extends Component {
  static propTypes = {
    load: PropTypes.func.isRequired,
    children: PropTypes.node.isRequired
  }

  state = {
    component: null
  }

  toggleFoucClass () {
    const root = document.getElementById('react-app')
    if (root.hasClass('fouc')) {
      root.removeClass('fouc')
    } else {
      root.addClass('fouc')
    }
  }

  componentWillMount () {
    this.toggleFoucClass()
  }

  componentDidMount () {
    this.props.load()
      .then((component) => {
        setTimeout(() => this.toggleFoucClass(), 0)
        this.setState(() => ({
          component: component.default
        }))
      })
  }

  render () {
    return this.props.children(this.state.component)
  }
}

const asyncRoute = (importFunc) =>
  (props) => (
    <AsyncImport load={importFunc}>
      {(Component) => {
        return Component === null
          ? <Loader loading />
          : <Component {...props} />
      }}
    </AsyncImport>
  )

export default asyncRoute

hasClassaddClassremoveClass是可对DOM类属性进行操作的polyfills.

hasClass, addClass, removeClass are polyfills which operates on DOM class attribute.

Loader是显示微调器的自定义组件.

Loader is a custom component which shows spinner.

为什么setTimeout?

仅因为我们需要在第二个刻度中删除fouc类.否则,它将与渲染Component相同.这样就行不通了.

Just because we need to remove fouc class in the second tick. Otherwise it would happen in the same as rendering the Component. So it won't work.

正如您在AsyncImport组件中看到的那样,我们通过添加fouc类来修改react根容器.因此,为了清楚起见,HTML:

As you can see in the AsyncImport component we modify react root container by adding fouc class. So HTML for clarity:

<html lang="en">
<head></head>
<body>
  <div id="react-app"></div>
</body>
</html>

还有另一个难题:

#react-app.fouc
    .page-layout *
        visibility: hidden

在导入特定组件(即:HomeExample)时要应用的ass.

sass to apply when importing of specific component (ie.: Home, Example) takes place.

为什么不display: none?

因为我们要使依赖于父级宽度,高度或任何其他css规则的所有组件都能正确呈现.

Because we want to have all components which rely on parent width, height or any other css rule to be properly rendered.

主要假设是隐藏所有元素,直到复合准备好向我们展示渲染的内容为止.首先它触发asyncRoute函数,该函数向我们显示Loader,直到Component挂载并渲染.同时,在AsyncImport中,我们通过在反应根DOM元素上使用类fouc来切换内容的可见性.当所有内容加载完毕后,该显示所有内容了,因此我们删除了该类.

The main assumption was to hide all elements until compoment gets ready to show us rendered content. First it fires asyncRoute function which shows us Loader until Component mounts and renders. In the meantime in AsyncImport we switch visibility of content by using a class fouc on react root DOM element. When everything loads, it's time to show everything up, so we remove that class.

希望有帮助!

文章,采用了动态导入的想法(我认为)来自反应可加载.

This article, which idea of dynamic import has been taken (I think) from react-loadable.

https://turkus.github.io/2018/06/06/fouc-react/

这篇关于如何在React.js中解析FOUC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆