Это пример со страницы приложения Google AdSense. Экран загрузки, отображаемый до главной страницы, отображается после.
Я не знаю, как сделать то же самое с React, потому что, если я создаю экран загрузки, отображаемый компонентом React, он не отображается во время загрузки страницы, потому что ему нужно ждать, пока DOM будет отображаться раньше.
Обновлено :
Я привел пример своего подхода, установив загрузчик экрана index.html
и удалив его в componentDidMount()
методе жизненного цикла React .
reactjs
asynchronous
redux
Тхань Нгуен
источник
источник
Ответы:
Это можно сделать, поместив значок загрузки в ваш html-файл (например, index.html), чтобы пользователи увидели значок сразу после загрузки html-файла.
Когда ваше приложение завершит загрузку, вы можете просто удалить этот значок загрузки в хуке жизненного цикла, я обычно делаю это в
componentDidMount
.источник
Цель
Когда страница html отображается, немедленно отобразите счетчик (пока React загружается) и скройте его после того, как React будет готов.
Поскольку счетчик отображается в чистом HTML / CSS (вне домена React), React не должен напрямую управлять процессом отображения / скрытия, а реализация должна быть прозрачной для React.
Решение 1.Пустой псевдокласс
Поскольку вы визуализируете реакцию в контейнер DOM -
<div id="app"></div>
, вы можете добавить счетчик в этот контейнер, и когда реакция загрузится и отобразится, счетчик исчезнет.Вы не можете добавить элемент DOM (например, div) в корень реакции, поскольку React заменит содержимое контейнера, как только он
ReactDOM.render()
будет вызван. Даже если выnull
выполните рендеринг , контент все равно будет заменен комментарием -<!-- react-empty: 1 -->
. Это означает, что если вы хотите отобразить загрузчик во время монтирования основного компонента, данные загружаются, но на самом деле ничего не отображается, разметка загрузчика, размещенная внутри контейнера (<div id="app"><div class="loader"></div></div>
например), не будет работать.Обходной путь - добавить класс счетчика в контейнер реакции и использовать
:empty
псевдокласс . Счетчик будет виден, пока в контейнер ничего не отображается (комментарии не учитываются). Как только response отобразит что-то кроме комментария, загрузчик исчезнет.Пример 1
В этом примере вы можете увидеть компонент, который рендерится,
null
пока не будет готов. Контейнер также является загрузчиком<div id="app" class="app"></div>
, а класс загрузчика будет работать, только если он:empty
(см. Комментарии в коде):Показать фрагмент кода
class App extends React.Component { state = { loading: true }; componentDidMount() { // this simulates an async action, after which the component will render the content demoAsyncCall().then(() => this.setState({ loading: false })); } 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> ); } } function demoAsyncCall() { return new Promise((resolve) => setTimeout(() => resolve(), 2500)); } 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 -->
Пример 2
Разновидностью использования
:empty
псевдокласса для отображения / скрытия селектора является установка счетчика как родственного элемента для контейнера приложения и его отображение до тех пор, пока контейнер пуст, с помощью соседнего родственного комбинатора (+
):Показать фрагмент кода
class App extends React.Component { state = { loading: true }; componentDidMount() { // this simulates an async action, after which the component will render the content demoAsyncCall().then(() => this.setState({ loading: false })); } 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> ); } } function demoAsyncCall() { return new Promise((resolve) => setTimeout(() => resolve(), 2500)); } 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>
Решение 2. Передайте «обработчики» счетчиков в качестве реквизита.
Чтобы иметь более детальный контроль над состоянием отображения счетчиков, создайте две функции
showSpinner
иhideSpinner
и передайте их корневому контейнеру через props. Функции могут управлять DOM или делать все необходимое для управления счетчиком. Таким образом, React не знает о «внешнем мире» и ему не нужно напрямую контролировать DOM. Вы можете легко заменить функции для тестирования или, если вам нужно изменить логику, и передать их другим компонентам в дереве React.Пример 1
Показать фрагмент кода
const loader = document.querySelector('.loader'); // if you want to show the loader when React loads data again const showLoader = () => loader.classList.remove('loader--hide'); const hideLoader = () => loader.classList.add('loader--hide'); class App extends React.Component { componentDidMount() { this.props.hideLoader(); } render() { return ( <div>I'm the app</div> ); } } // the setTimeout simulates the time it takes react to load, and is not part of the solution setTimeout(() => // the show/hide functions are passed as props ReactDOM.render( <App hideLoader={hideLoader} showLoader={showLoader} />, document.getElementById('app') ) , 1000);
.loader { 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; transition: opacity 0.3s; } .loader--hide { opacity: 0; } @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"></div> <div class="loader"></div>
Пример 2 - крючки
В этом примере
useEffect
крючок используется для скрытия счетчика после монтирования компонента.Показать фрагмент кода
const { useEffect } = React; const loader = document.querySelector('.loader'); // if you want to show the loader when React loads data again const showLoader = () => loader.classList.remove('loader--hide'); const hideLoader = () => loader.classList.add('loader--hide'); const App = ({ hideLoader }) => { useEffect(hideLoader, []); return ( <div>I'm the app</div> ); } // the setTimeout simulates the time it takes react to load, and is not part of the solution setTimeout(() => // the show/hide functions are passed as props ReactDOM.render( <App hideLoader={hideLoader} showLoader={showLoader} />, document.getElementById('app') ) , 1000);
.loader { 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; transition: opacity 0.3s; } .loader--hide { opacity: 0; } @keyframes load8 { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="app"></div> <div class="loader"></div>
источник
return null
добавляет комментарий, который будет отображаться как пустой экран. Псевдокласс: empty работает вместе с ним,return null
поскольку он игнорирует комментарии при определении, пуст ли контейнер.Обходной путь для этого:
В вашей функции рендеринга сделайте что-то вроде этого:
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 и т. Д.) И показывает настраиваемый загрузчик.
Хорошо работал с нашими проектами реагирования / ретрансляции (обрабатывает изменения навигации, используя response-router, запросы ретрансляции) (не связан; использовал pace.js для наших проектов, и он отлично работал)
источник
public/index.html
и выберите стиль. это мертвенно простой, потрясающий плагин. Спасибо.Это произойдет до
ReactDOM.render()
того, как рут получит контроль<div>
. Т.е. ваше приложение не будет установлено до этого момента.Таким образом, вы можете добавить свой загрузчик в свой
index.html
файл внутри корня<div>
. И это будет видно на экране, пока React не вступит во владение.Вы можете использовать любой элемент загрузчика, который вам больше подходит (например,
svg
с анимацией).Вам не нужно удалять его ни в одном методе жизненного цикла. React заменит любых дочерних элементов своего корня
<div>
на ваши отрисованные<App/>
, как мы видим на GIF-изображении ниже.Пример на CodeSandbox
index.html
<head> <style> .svgLoader { animation: spin 0.5s linear infinite; margin: auto; } .divLoader { width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> </head> <body> <div id="root"> <div class="divLoader"> <svg class="svgLoader" viewBox="0 0 1024 1024" width="10em" height="10em"> <path fill="lightblue" d="PATH FOR THE LOADER ICON" /> </svg> </div> </div> </body>
index.js
Используется
debugger
для проверки страницы передReactDOM.render()
запуском.import React from "react"; import ReactDOM from "react-dom"; import "./styles.css"; function App() { return ( <div className="App"> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> </div> ); } debugger; // TO INSPECT THE PAGE BEFORE 1ST RENDER const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);
источник
Когда ваше приложение React является огромным, ему действительно нужно время, чтобы оно заработало после загрузки страницы. Скажем, вы монтируете свою React-часть приложения в
#app
. Обычно этот элемент в вашем index.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>
После загрузки страницы пользователь сразу же увидит исходное содержимое index.html. Вскоре после этого, когда React будет готов подключить всю иерархию визуализированных компонентов к этому узлу DOM, пользователь увидит реальное приложение.
Заметьте
class
, нетclassName
. Это потому, что вам нужно поместить это в свой html файл.Если вы используете SSR, все будет проще, потому что пользователь фактически увидит реальное приложение сразу после загрузки страницы.
источник
В настоящее время мы можем использовать хуки и в React 16.8:
import React, { useState, useEffect } from 'react'; const App = () => { const [ spinner, setSpinner ] = useState(true); // It will be executed before rendering useEffect(() => { setTimeout(() => setSpinner(false), 1000) }, []); // [] means like componentDidMount return !spinner && <div>Your content</div>; }; export default App;
источник
Недавно мне пришлось столкнуться с этой проблемой, и я нашел решение, которое мне подходит. Однако я пробовал решение @Ori Drori, описанное выше, и, к сожалению, оно не сработало (были некоторые задержки + мне не нравится использование
setTimeout
функции там).Вот что я придумал:
index.html
файлВнутри
head
тега - стили для индикатора:<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
файла (в функции рендеринга):const spinner = document.getElementById('spinner'); if (spinner && !spinner.hasAttribute('hidden')) { spinner.setAttribute('hidden', 'true'); }
Как это работает?
Когда первый компонент (в моем приложении он также
app.js
в большинстве случаев) монтируется правильно,spinner
он скрывается с применениемhidden
к нему атрибута.Что еще важнее добавить -
!spinner.hasAttribute('hidden')
условие не позволяет добавлятьhidden
атрибут в счетчик при каждом монтировании компонента, поэтому на самом деле он будет добавлен только один раз, когда загружается все приложение.источник
Установка тайм-аута в 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; } }
источник
Я использую пакет npm response -progress-2 , который не зависит от нуля и отлично работает в ReactJS.
https://github.com/milworm/react-progress-2
Установка:
npm install react-progress-2
Включите в свой проект response-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 вызовов hide, чтобы скрыть индикатор, или вы можете использоватьProgress.hideAll()
.источник
Я также использую React в своем приложении. Для запросов я использую перехватчики axios, поэтому отличный способ сделать экран загрузчика (полностраничным, как вы показали пример) - это добавить класс или идентификатор, например, к телу внутри перехватчиков (здесь код из официальной документации с некоторым настраиваемым кодом):
// Add a request interceptor axios.interceptors.request.use(function (config) { // Do something before request is sent document.body.classList.add('custom-loader'); return config; }, function (error) { // Do something with request error return Promise.reject(error); }); // Add a response interceptor axios.interceptors.response.use(function (response) { // Do something with response data document.body.classList.remove('custom-loader'); return response; }, function (error) { // Do something with response error return Promise.reject(error); });
А затем просто внедрите в CSS свой загрузчик с псевдоэлементами (или добавьте класс или идентификатор к другому элементу, а не к телу, как вам нравится) - вы можете установить цвет фона на непрозрачный или прозрачный и т. Д. Пример:
custom-loader:before { background: #000000; content: ""; position: fixed; ... } custom-loader:after { background: #000000; content: "Loading content..."; position: fixed; color: white; ... }
источник
Измените расположение файла index.html в общей папке. Скопируйте изображение в то же место, что и index.html в общей папке. Затем замените часть содержимого index.html, содержащую
<div id="root"> </div>
теги, на приведенный ниже html-код.<div id="root"> <img src="logo-dark300w.png" alt="Spideren" style="vertical-align: middle; position: absolute; top: 50%; left: 50%; margin-top: -100px; /* Half the height */ margin-left: -250px; /* Half the width */" /> </div>
Теперь во время загрузки посередине страницы появится логотип. И через несколько секунд будет заменен React.
источник
Вам не нужно так много усилий, вот базовый пример.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> <link rel="apple-touch-icon" href="logo192.png" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <title>Title</title> <style> body { margin: 0; } .loader-container { width: 100vw; height: 100vh; display: flex; overflow: hidden; } .loader { margin: auto; border: 5px dotted #dadada; border-top: 5px solid #3498db; border-radius: 50%; width: 100px; height: 100px; -webkit-animation: spin 2s linear infinite; animation: spin 2s linear infinite; } @-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"> <div class="loader-container"> <div class="loader"></div> </div> </div> </body> </html>
Вы можете поэкспериментировать
HTML
иCSS
сделать так, чтобы он выглядел как ваш пример.источник
Я также использовал ответ @Ori Drori, и мне удалось заставить его работать. По мере роста вашего кода React будут скомпилированы пакеты, которые клиентский браузер должен будет загрузить при первом доступе. Это создает проблемы с пользовательским интерфейсом, если вы не справляетесь с этим должным образом.
Что я добавил в ответ @Ori, так это добавить и выполнить функцию onload в атрибуте index.html on onload тега body, так что загрузчик исчезнет после того, как все будет полностью загружено в обзоре, см. Фрагмент ниже:
<html> <head> <style> .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); } } </style> <script> function onLoad() { var loader = document.getElementById("cpay_loader");loader.className = "";} </script> </head> <body onload="onLoad();"> more html here..... </body> </html>
источник
Самый важный вопрос: что вы подразумеваете под «загрузкой»? Если вы говорите о монтируемом физическом элементе, некоторые из первых ответов здесь отличные. Однако, если первое, что делает ваше приложение, - это проверка аутентификации, на самом деле вы загружаете данные из бэкэнда, передал ли пользователь файл cookie, который помечает его как авторизованного или неавторизованного пользователя.
Это основано на redux, но вы можете легко изменить его на модель простого состояния реакции.
создатель действия:
export const getTodos = () => { return async dispatch => { let res; try { res = await axios.get('/todos/get'); dispatch({ type: AUTH, auth: true }); dispatch({ type: GET_TODOS, todos: res.data.todos }); } catch (e) { } finally { dispatch({ type: LOADING, loading: false }); } }; };
Часть finally означает, авторизован пользователь или нет, экран загрузки уходит после получения ответа.
Вот как может выглядеть загружаемый компонент:
class App extends Component { renderLayout() { const { loading, auth, username, error, handleSidebarClick, handleCloseModal } = this.props; if (loading) { return <Loading />; } return ( ... ); } ... componentDidMount() { this.props.getTodos(); } ... render() { return this.renderLayout(); } }
Если state.loading правдив, мы всегда будем видеть экран загрузки. В componentDidMount мы вызываем нашу функцию getTodos, которая является создателем действия, который превращает state.loading в ложный, когда мы получаем ответ (что может быть ошибкой). Наш компонент обновляется, снова вызывает рендеринг, и на этот раз экрана загрузки нет из-за оператора if.
источник
Запуск приложения React основан на загрузке основного пакета. Приложение React запускается только после загрузки основного пакета в браузере. Это верно даже в случае архитектуры отложенной загрузки. Но дело в том, что мы не можем точно указать название каких-либо пакетов. Потому что webpack будет добавлять хеш-значение в конец каждого пакета во время выполнения команды npm run build. Конечно, мы можем избежать этого, изменив настройки хеширования, но это серьезно повлияет на проблему данных кеша в браузере. Браузеры могут не использовать новую версию из-за того же имени пакета. . нам нужен подход webpack + js + CSS, чтобы справиться с этой ситуацией.
измените public / index.html, как показано ниже
<!DOCTYPE html> <html lang="en" xml:lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=3.0, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <!-- manifest.json provides metadata used when your web app is added to the homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <style> .percentage { position: absolute; top: 50%; left: 50%; width: 150px; height: 150px; border: 1px solid #ccc; background-color: #f3f3f3; -webkit-transform: translate(-50%, -50%); -ms-transform: translate(-50%, -50%); transform: translate(-50%, -50%); border: 1.1em solid rgba(0, 0, 0, 0.2); border-radius: 50%; overflow: hidden; display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; } .innerpercentage { font-size: 20px; } </style> <script> function showPercentage(value) { document.getElementById('percentage').innerHTML = (value * 100).toFixed() + "%"; } var req = new XMLHttpRequest(); req.addEventListener("progress", function (event) { if (event.lengthComputable) { var percentComplete = event.loaded / event.total; showPercentage(percentComplete) // ... } else { document.getElementById('percentage').innerHTML = "Loading.."; } }, false); // load responseText into a new script element req.addEventListener("load", function (event) { var e = event.target; var s = document.createElement("script"); s.innerHTML = e.responseText; document.documentElement.appendChild(s); document.getElementById('parentDiv').style.display = 'none'; }, false); var bundleName = "<%= htmlWebpackPlugin.files.chunks.main.entry %>"; req.open("GET", bundleName); req.send(); </script> <!-- Notice the use of %PUBLIC_URL% in the tags above. It will be replaced with the URL of the `public` folder during the build. Only files inside the `public` folder can be referenced from the HTML. Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> <title>App Name</title> <link href="<%= htmlWebpackPlugin.files.chunks.main.css[0] %>" rel="stylesheet"> </head> <body> <noscript> You need to enable JavaScript to run this app. </noscript> <div id="parentDiv" class="percentage"> <div id="percentage" class="innerpercentage">loading</div> </div> <div id="root"></div> <!-- This HTML file is a template. If you open it directly in the browser, you will see an empty page. You can add webfonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the <body> tag. To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> </body> </html>
В вашей производственной конфигурации веб-пакета измените параметр HtmlWebpackPlugin на ниже
new HtmlWebpackPlugin({ inject: false, ...
Возможно, вам понадобится использовать команду «eject», чтобы получить файл конфигурации. последний веб-пакет может иметь возможность настроить HtmlWebpackPlugin без извлечения проекта.
источник
А как насчет использования темпа
Используйте этот адрес ссылки здесь.
https://github.hubspot.com/pace/docs/welcome/
1. На их веб-сайте выберите нужный стиль и вставьте в index.css.
2. перейдите в cdnjs Скопируйте ссылку для Pace Js и добавьте в свои теги скрипта в public / index.html
3. Он автоматически определяет веб-загрузки и отображает темп в верхней части браузера.
Вы также можете изменить высоту и анимацию в CSS.
источник
это моя реализация, основанная на ответах
./public/index.html
<!DOCTYPE html> <html lang="en"> <head> <title>React App</title> <style> .preloader { display: flex; justify-content: center; } .rotate { animation: rotation 1s infinite linear; } .loader-hide { display: none; } @keyframes rotation { from { transform: rotate(0deg); } to { transform: rotate(359deg); } } </style> </head> <body> <div class="preloader"> <img src="https://i.imgur.com/kDDFvUp.png" class="rotate" width="100" height="100" /> </div> <div id="root"></div> </body> </html>
./src/app.js
import React, { useEffect } from "react"; import "./App.css"; const loader = document.querySelector(".preloader"); const showLoader = () => loader.classList.remove("preloader"); const addClass = () => loader.classList.add("loader-hide"); const App = () => { useEffect(() => { showLoader(); addClass(); }, []); return ( <div style={{ display: "flex", justifyContent: "center" }}> <h2>App react</h2> </div> ); }; export default App;
источник