如何在React.js中解析FOUC [英] How to resolve FOUC in React.js
问题描述
我已经从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
hasClass
,addClass
,removeClass
是可对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
在导入特定组件(即:Home
,Example
)时要应用的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屋!