Я создал сайт response.js из приложения create-response-app. Но в производственном режиме есть FOUC, потому что стили загружаются после рендеринга HTML.
Есть ли способ решить эту проблему? Я искал ответы в Google, но пока не нашел подходящего.






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,removeClassare polyfills which operates on DOM class attribute.
Loaderis a custom component which shows spinner.
Почему 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).
Почему не display: none?
Потому что мы хотим, чтобы все компоненты, которые полагаются на родительскую ширину, высоту или любое другое правило CSS, правильно отображались.
Основное предположение заключалось в том, чтобы скрыть все элементы до тех пор, пока композиция не будет готова показать нам визуализированный контент. Сначала он запускает функцию asyncRoute, которая показывает нам Loader, пока Component не смонтирует и не отрендерит. Тем временем в AsyncImport мы переключаем видимость контента с помощью класса fouc на корневом элементе DOM реакции. Когда все загружается, пора все показать, поэтому мы удаляем этот класс.
Надеюсь, это поможет!
Это статья, идея динамического импорта которого была взята (я думаю) из реагирующий.
https://turkus.github.io/2018/06/06/fouc-react/
Один вопрос - где мне разместить css для 'fouc', 'page-layout'
@ThunderboltEngineer, вы можете поместить его даже в свой HTML-код в голове, но помните, что это нахально.
Вы выбросили свой проект?