FOUC
FOUC - так называемая Флэш нестандартного содержимого может быть столь же проблематичным, как и многие попытки решить эту проблему.
К точке
Рассмотрим следующую конфигурацию маршрутизации ( реагирующий маршрутизатор ):
...
<PageLayout>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/example' component={Example} />
<Switch>
</PageLayout>
...
, где PageLayout
- это простое hoc , содержащий упаковщик div с классом page-layout
и возвращающий его потомки.
Теперь давайте сосредоточимся на рендеринге компонента на основе маршрута.Обычно вы используете в качестве component
команду React 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.
Loader
- это пользовательский компонент, отображающий счетчик.
Почему 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
) занимаетplace.
Почему бы не display: none
?
Поскольку мы хотим, чтобы все компоненты, которые зависят от родительской ширины, высоты или любого другого правила CSS, были правильно отображены.
Как это работает?
Основным предположением было скрыть все элементы до тех пор, пока компоновщик не будет готов показать нам визуализированный контент.Сначала он запускает функцию asyncRoute
, которая показывает нам Loader
до Component
монтирования и рендеринга.Тем временем в AsyncImport
мы переключаем видимость контента, используя класс fouc
для реагирующего корневого элемента DOM.Когда все загружается, пришло время показать все, поэтому мы удаляем этот класс.
Надеюсь, это поможет!
Благодаря
Эта статья ,какая идея динамического импорта была взята (я думаю) из реагирующая загрузка .
Источник
https://turkus.github.io/2018/06/06/fouc-react/