FOUC
FOUC--所谓的闪烁的无样式内容可能与解决这个问题的许多尝试一样有问题。
说到重点
让我们考虑以下路由配置(反应路由器 https://github.com/ReactTraining/react-router):
...
<PageLayout>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/example' component={Example} />
<Switch>
</PageLayout>
...
where PageLayout
是一个简单的hoc https://reactjs.org/docs/higher-order-components.html,包含 div 包装page-layout
班级并返回其孩子。
现在我们重点关注基于路由的组件渲染。通常你会使用 ascomponent
支持 ReactCompoment
。但在我们的例子中,我们需要动态获取它,以应用有助于我们避免 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
是一个显示微调器的自定义组件。
Why setTimeout
?
只是因为我们需要删除fouc
第二个刻度线的班级。否则,它会在渲染组件时发生。所以这是行不通的。
正如你在AsyncImport
我们通过添加来修改反应根容器的组件fouc
班级。为了清楚起见,HTML 如下:
<html lang="en">
<head></head>
<body>
<div id="react-app"></div>
</body>
</html>
还有另一块拼图:
#react-app.fouc
.page-layout *
visibility: hidden
导入特定组件时应用 sass(即:Home
, Example
)发生。
Why not display: none
?
因为我们希望所有依赖父级宽度、高度或任何其他 CSS 规则的组件都能正确呈现。
怎么运行的?
主要假设是隐藏所有元素,直到组件准备好向我们显示渲染的内容。首先它会点火asyncRoute
函数向我们展示了Loader
until Component
安装和渲染。其间在AsyncImport
我们通过使用类来切换内容的可见性fouc
在反应根 DOM 元素上。当所有内容加载完毕后,就该显示所有内容了,因此我们删除该类。
希望有帮助!
谢谢
This article https://tylermcginnis.com/react-router-code-splitting/,动态导入的想法(我认为)来自反应可加载 https://github.com/jamiebuilds/react-loadable.
Source
https://turkus.github.io/2018/06/06/fouc-react/ https://turkus.github.io/2018/06/06/fouc-react/