我已经从create-react-app构建了react.js网站。 但是在生产模式中,存在FOUC,因为在呈现html之后加载样式。
有什么方法可以解决这个问题吗?我一直在谷歌搜索答案,但还没找到合适的答案。
答案 0 :(得分:2)
FOUC - 所谓的 Flash of Unstyled Content 可能与解决此问题的许多尝试一样非常棘手。
让我们考虑以下路由配置(react-router):
...
<PageLayout>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/example' component={Example} />
<Switch>
</PageLayout>
...
其中PageLayout
是一个简单的hoc,包含带有page-layout
类的div包装并返回它的子级。
现在,让我们关注基于路线的组件渲染。通常你会使用component
prop作为反应Compoment
。但在我们的情况下,我们需要动态地获取它,以应用有助于我们避免FOUC的功能。所以我们的代码看起来像这样:
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
模块的样子:
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类属性进行操作的polyfill。
Loader
是一个显示微调器的自定义组件。
为什么setTimeout
?
仅仅因为我们需要在第二个刻度中移除fouc
类。否则它将与渲染Component相同。所以它不会工作。
正如您在AsyncImport
组件中看到的那样,我们通过添加fouc
类来修改反应根容器。所以HTML是为了清晰起见:
<html lang="en">
<head></head>
<body>
<div id="react-app"></div>
</body>
</html>
另一个难题:
#react-app.fouc
.page-layout *
visibility: hidden
在导入特定组件(即:Home
,Example
)时应用。
为什么不display: none
?
因为我们希望所有依赖于父宽度,高度或任何其他css规则的组件都能正确呈现。
主要假设是隐藏所有元素,直到组件准备好向我们展示渲染内容。首先,它会触发asyncRoute
函数,该函数会在Loader
安装和渲染之前向我们显示Component
。与此同时,在AsyncImport
中,我们通过在反应根DOM元素上使用类fouc
来切换内容的可见性。当一切都加载时,是时候展示一切,所以我们删除了那个类。
希望有所帮助!
此article,我认为动态导入的想法来自react-loadable。