React-отображение экрана загрузки во время рендеринга DOM?
это пример со страницы приложения Google Adsense. Экран загрузки, отображаемый перед главной страницей, отображается после.

Я не знаю, как сделать то же самое с React, потому что если я делаю экран загрузки, отображаемый компонентом React, он не отображается во время загрузки страницы, потому что он должен ждать DOM, отображаемого раньше.
Обновлено:
Я сделал пример моего подхода, поставив загрузчик экрана index.html и удалить его в React componentDidMount() метод жизненного цикла.
пример:
https://nguyenbathanh.github.io
источник:
https://github.com/nguyenbathanh/react-loading-screen
8 ответов:
Это можно сделать, поместив значок загрузки в HTML-файл (индекс.html for ex), так что пользователи видят значок сразу после загрузки файла html.
когда ваше приложение завершает загрузку, вы можете просто удалить этот значок загрузки в крючке жизненного цикла, я обычно делаю это в
componentDidMount.
так как вы оказываете реагировать в контейнер DOM -
<div id="app"></div>, вы можете добавить прядильщик в этот контейнер, и когда react загрузится и отобразится, прядильщик исчезнет.проблема:
React заменит содержимое контейнера, как только
ReactDOM.render()называется. Даже если вы рендеритеnull, содержание все равно будет заменено комментарием -<!-- react-empty: 1 -->. Это означает, что если вы хотите отобразить загрузчик во время рендеринга react, загрузчик разметка, размещенная внутри контейнера (<div id="app"><div class="loader"></div></div>например) не будет работать.устранение:
мое решение состоит в том, чтобы добавить класс загрузчика непосредственно в контейнер, но с
:emptyпсевдо-класс. Прядильщик будет виден, пока ничего не отображается в контейнере (комментарии не учитываются). Как только react отобразит элемент, загрузчик исчезнет.
в примере вы можете увидеть компонент это делает
nullпока он не готов. Контейнер также является загрузчиком -<div id="app" class="app"></div>, и класс загрузчика будет работать только если это:empty(см. комментарии в коде):class App extends React.Component { state = { loading: true }; componentDidMount() { setTimeout(() => this.setState({ loading: false }), 1500); // simulates an async action, and hides the spinner } render() { const { loading } = this.state; if(loading) { // if your component doesn't have to wait for an async action, remove this block return null; // render null when app is not ready } return ( <div>I'm the app</div> ); } } ReactDOM.render( <App />, document.getElementById('app') );.loader:empty { position: absolute; top: calc(50% - 4em); left: calc(50% - 4em); width: 6em; height: 6em; border: 1.1em solid rgba(0, 0, 0, 0.2); border-left: 1.1em solid #000000; border-radius: 50%; animation: load8 1.1s infinite linear; } @keyframes load8 { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.js"></script> <div id="app" class="loader"></div> <!-- add class loader to container -->вариант использования
:emptyпсевдо-класс to / show hide selector, устанавливает счетчик в качестве элемента-брата в контейнер приложения и показывает его до тех пор, пока контейнер пуст, используя рядом родственный комбинатор (+):class App extends React.Component { state = { loading: true }; componentDidMount() { setTimeout(() => this.setState({ loading: false }), 2500); // simulates loading of data } render() { const { loading } = this.state; if(loading) { // if your component doesn't have to wait for async data, remove this block return null; // render null when app is not ready } return ( <div>I'm the app</div> ); } } ReactDOM.render( <App />, document.getElementById('app') );#app:not(:empty) + .sk-cube-grid { display: none; } .sk-cube-grid { width: 40px; height: 40px; margin: 100px auto; } .sk-cube-grid .sk-cube { width: 33%; height: 33%; background-color: #333; float: left; animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out; } .sk-cube-grid .sk-cube1 { animation-delay: 0.2s; } .sk-cube-grid .sk-cube2 { animation-delay: 0.3s; } .sk-cube-grid .sk-cube3 { animation-delay: 0.4s; } .sk-cube-grid .sk-cube4 { animation-delay: 0.1s; } .sk-cube-grid .sk-cube5 { animation-delay: 0.2s; } .sk-cube-grid .sk-cube6 { animation-delay: 0.3s; } .sk-cube-grid .sk-cube7 { animation-delay: 0s; } .sk-cube-grid .sk-cube8 { animation-delay: 0.1s; } .sk-cube-grid .sk-cube9 { animation-delay: 0.2s; } @keyframes sk-cubeGridScaleDelay { 0%, 70%, 100% { transform: scale3D(1, 1, 1); } 35% { transform: scale3D(0, 0, 1); } }<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.js"></script> <div id="app"></div> <!-- add class loader to container --> <div class="sk-cube-grid"> <div class="sk-cube sk-cube1"></div> <div class="sk-cube sk-cube2"></div> <div class="sk-cube sk-cube3"></div> <div class="sk-cube sk-cube4"></div> <div class="sk-cube sk-cube5"></div> <div class="sk-cube sk-cube6"></div> <div class="sk-cube sk-cube7"></div> <div class="sk-cube sk-cube8"></div> <div class="sk-cube sk-cube9"></div> </div>
обходной путь для этого:
в ваши функции render сделать что-то вроде этого:
constructor() { this.state = { isLoading: true } } componentDidMount() { this.setState({isLoading: false}) } render() { return( this.state.isLoading ? *showLoadingScreen* : *yourPage()* ) }инициализировать isLoading как true в конструкторе и false на componentDidMount
Если кто-то ищет библиотеку drop-in, zero-config и zero-dependencies для приведенного выше варианта использования, попробуйте pace.js (http://github.hubspot.com/pace/docs/welcome/).
он автоматически подключается к событиям (ajax, readyState, history pushstate, JS event loop и т. д.) и показывает настраиваемый загрузчик.
хорошо работал с нашими проектами react / relay (обрабатывает изменения навигации с помощью react-router, запросы ретрансляции) (Не affliated; использовали темпами.JS для наших проекты и это сработало отлично)
когда ваше приложение React является массивным, ему действительно требуется время, чтобы встать и запустить после загрузки страницы. Скажем, вы монтируете свою часть приложения React в
#app. Как правило, это элемент в вашем индексе.html - это просто пустой div:<div id="app"></div>вместо этого вы можете поместить туда несколько стилей и кучу изображений, чтобы они выглядели лучше между загрузкой страницы и первоначальным рендерингом приложения React в DOM:
<div id="app"> <div class="logo"> <img src="/my/cool/examplelogo.svg" /> </div> <div class="preload-title"> Hold on, it's loading! </div> </div>после загрузки страницы, пользователь сразу увидит исходное содержание индекса.формат html. Вскоре после этого, когда React будет готов подключить всю иерархию отрисованных компонентов к этому узлу DOM, пользователь увидит фактическое приложение.
Примечание
class, а неclassName. Это потому, что вам нужно поместить это в свой html-файл.
если вы используете SSR, все менее сложно, потому что пользователь фактически увидит реальное приложение сразу после загрузки страницы.
Я должен был иметь дело с этой проблемой недавно и придумал решение, которое работает просто отлично для меня. Тем не менее, я пробовал решение @Ori Drori выше, и, к сожалению, оно не сработало правильно (были некоторые задержки + мне не нравится использование
setTimeoutфункция есть).вот что я придумал:
index.htmlfileвнутри
headtag-стили для индикатора:<style media="screen" type="text/css"> .loading { -webkit-animation: sk-scaleout 1.0s infinite ease-in-out; animation: sk-scaleout 1.0s infinite ease-in-out; background-color: black; border-radius: 100%; height: 6em; width: 6em; } .container { align-items: center; background-color: white; display: flex; height: 100vh; justify-content: center; width: 100vw; } @keyframes sk-scaleout { 0% { -webkit-transform: scale(0); transform: scale(0); } 100% { -webkit-transform: scale(1.0); opacity: 0; transform: scale(1.0); } } </style>теперь в
bodyтеги:<div id="spinner" class="container"> <div class="loading"></div> </div> <div id="app"></div>а то очень простая логика, внутри
app.jsфайл (в функции render):const spinner = document.getElementById('spinner'); if (spinner && !spinner.hasAttribute('hidden')) { spinner.setAttribute('hidden', 'true'); }как это работает?
когда первый компонент (в моем приложении это
app.jsа также в большинстве случаев) монтируется правильно, тоspinnerскрывается с применениемhiddenатрибут к нему.что важнее добавить -
!spinner.hasAttribute('hidden')условие мешает добавить на блесну с каждым компонентом гору, так что на самом деле он будет добавлен только один раз, когда приложение загружает.
Я использую реагировать-Прогресс-2 пакет npm, который является нулевой зависимостью и отлично работает в ReactJS.
https://github.com/milworm/react-progress-2
установка:
npm install react-progress-2включить react-progress-2 / main.CSS для вашего проекта.
import "node_modules/react-progress-2/main.css";включить
react-progress-2и поместите его где-нибудь в верхнем компоненте, например:import React from "react"; import Progress from "react-progress-2"; var Layout = React.createClass({ render: function() { return ( <div className="layout"> <Progress.Component/> {/* other components go here*/} </div> ); } });теперь, когда вам нужно чтобы показать индикатор, просто позвоните
Progress.show(), например:loadFeed: function() { Progress.show(); // do your ajax thing. }, onLoadFeedCallback: function() { Progress.hide(); // render feed. }Пожалуйста, обратите внимание, что
showиhideвызовы складываются, поэтому после n-последовательных вызовов show вам нужно сделать N скрытых вызовов, чтобы скрыть индикатор, или вы можете использоватьProgress.hideAll().
установка таймаута в componentDidMount работает, но в моем приложении я получил предупреждение об утечке памяти. Попробуйте что-то вроде этого.
constructor(props) { super(props) this.state = { loading: true, } } componentDidMount() { this.timerHandle = setTimeout(() => this.setState({ loading: false }), 3500); } componentWillUnmount(){ if (this.timerHandle) { clearTimeout(this.timerHandle); this.timerHandle = 0; } }
Comments