React - Wyświetla ekran ładowania podczas renderowania DOM?

150

To jest przykład ze strony aplikacji Google Adsense. Ekran ładowania wyświetlany przed wyświetleniem strony głównej po.

wprowadź opis obrazu tutaj

Nie wiem, jak zrobić to samo z Reactem, ponieważ jeśli wykonam ekran ładowania renderowany przez komponent React, nie wyświetla się on podczas ładowania strony, ponieważ musi czekać na renderowanie DOM wcześniej.

Zaktualizowano :

Zrobiłem przykład mojego podejścia, umieszczając program ładujący ekran index.htmli usuwając go w componentDidMount()metodzie cyklu życia React .

Przykład i ekran ponownego ładowania .

Thanh Nguyen
źródło
Pokaż, co chcesz pokazać w zwykłym js, a następnie ukryj lub usuń z DOM po zamontowaniu reakcji. Wszystko, co musisz zrobić, to ukryć go przed kodem reakcyjnym.
FurkanO
To jest po prostu cudowne! Dziękuję Ci.
Arman Karimi

Odpowiedzi:

100

Można to zrobić, umieszczając ikonę ładowania w pliku html (np. Index.html), tak aby użytkownicy widzieli tę ikonę natychmiast po załadowaniu pliku html.

Po zakończeniu ładowania aplikacji możesz po prostu usunąć tę ikonę ładowania w haku cyklu życia, zwykle robię to w componentDidMount.

kkkkkkk
źródło
11
Jeśli zamontujesz komponent główny do węzła nadrzędnego tej ikony, nie ma nawet potrzeby usuwania go ręcznie. React wyczyści elementy potomne węzła montowania i umieści tam swój własny, nowo wyrenderowany DOM.
rishat
6
Nie umieszczam ikony wewnątrz węzła głównego aplikacji React, po prostu nie wydaje mi się to właściwe
kkkkkkk
171

Cel

Kiedy strona html jest renderowana, natychmiast wyświetl spinner (podczas ładowania Reacta) i ukryj go, gdy React będzie gotowy.

Ponieważ spinner jest renderowany w czystym HTML / CSS (poza domeną React), React nie powinien bezpośrednio kontrolować procesu pokazywania / ukrywania, a implementacja powinna być przezroczysta dla Reacta.

Rozwiązanie 1 - pseudoklasa: pusta

Ponieważ renderujesz reaguje na kontener DOM - <div id="app"></div> możesz dodać spinner do tego kontenera, a kiedy reakcja się załaduje i wyrenderuje, spinner zniknie.

Nie możesz dodać elementu DOM (na przykład elementu div) do elementu React root, ponieważ React zastąpi zawartość kontenera natychmiast po ReactDOM.render()wywołaniu. Nawet jeśli wyrenderujesz null, zawartość i tak zostanie zastąpiona komentarzem - <!-- react-empty: 1 -->. Oznacza to, że jeśli chcesz wyświetlić moduł ładujący podczas montowania głównego komponentu, dane są ładowane, ale w rzeczywistości nic nie jest renderowane, znacznik modułu ładującego umieszczony wewnątrz kontenera ( <div id="app"><div class="loader"></div></div>na przykład) nie zadziała.

Aby obejść ten problem, należy dodać klasę spinner do kontenera reagującego i użyć :emptypseudoklasy . Spinner będzie widoczny, o ile nic nie zostanie wyrenderowane w kontenerze (komentarze się nie liczą). Gdy tylko reakcja wyświetli coś innego niż komentarz, moduł ładujący zniknie.

Przykład 1

W tym przykładzie widać komponent, który renderuje się, nulldopóki nie będzie gotowy. Kontener jest również modułem ładującym - <div id="app" class="app"></div>a klasa modułu ładującego będzie działać tylko wtedy, gdy jest :empty(zobacz komentarze w kodzie):

Przykład 2

Odmianą użycia :emptypseudoklasy do pokazania / ukrycia selektora jest ustawienie pokrętła jako elementu siostrzanego w kontenerze aplikacji i pokazanie go, dopóki kontener jest pusty, przy użyciu sąsiedniego łącznika siostrzanego ( +):


Rozwiązanie 2 - Podaj "handlerów" spinnerów jako rekwizyty

Aby mieć bardziej szczegółową kontrolę nad stanem wyświetlania przędzarek, utwórz dwie funkcje showSpinneri hideSpinneri przekaż je do kontenera głównego za pomocą rekwizytów. Funkcje mogą manipulować DOM lub robić wszystko, co potrzebne, aby sterować przędzarką. W ten sposób React nie jest świadomy „świata zewnętrznego” ani nie musi bezpośrednio kontrolować DOM. Możesz łatwo zamienić funkcje do testowania lub jeśli potrzebujesz zmienić logikę, i możesz przekazać je innym komponentom w drzewie React.

Przykład 1

Przykład 2 - haki

W tym przykładzie zastosowano useEffecthaczyk do ukrycia kołpaka po zamontowaniu komponentu.

Ori Drori
źródło
Czy mógłbyś wyjaśnić, gdzie powinny znajdować się ostatnie 2 sekcje kodu? Pierwsza jest wyraźnie w pliku src javascript dla komponentu reagowania, trzecia, jak sądzę, znajduje się w szablonie html, który ma być renderowany przez wspomniany plik js, ale gdzie idzie druga?
levraininjaneer
1
Drugi to CSS. Użyłem globalnego CSS, ale możesz użyć modułów CSS lub CSS w JS. Trzeci to plik HTML, który w razie potrzeby może zawierać znaczniki spinner (drugi przykład).
Ori Drori
Ten limit czasu nie jest dobry, jeśli weźmie się pod uwagę wydajność.
dryleaf
4
@dryleaf - setTimeout nie jest częścią rozwiązania. Symuluje oczekiwanie na akcję asynchroniczną przed renderowaniem treści.
Ori Drori
Stosuję podobne podejście. Nie mogę znaleźć niczego w pakiecie webpack, który mógłby pomóc mi zepsuć pamięć podręczną dla pliku css wymaganego dla programu ładującego. Możesz pomóc?
hamza-jutt
40

Sposób obejścia tego problemu:

W swojej funkcji renderującej zrób coś takiego:

constructor() {
    this.state = { isLoading: true }
}

componentDidMount() {
    this.setState({isLoading: false})
}

render() {
    return(
        this.state.isLoading ? *showLoadingScreen* : *yourPage()*
    )
}

Zainicjuj isLoading jako true w konstruktorze i false na componentDidMount

Amoolya S Kumar
źródło
Kiedy wywołaliśmy metodę Ajax w celu załadowania danych do komponentów potomnych. componentDidMount wywołane przed wypełnieniem danych składnika podrzędnego. Jak rozwiązujemy tego rodzaju problemy?
dush88c
2
W przypadku cyklu życia montażu jest w porządku, czy chcesz dodać coś do cyklu życia aktualizacji?
zakir
muszę to robić na wszystkich stronach, czy tylko we wpisie aplikacji
Pedro JR
16

Jeśli ktoś szuka biblioteki typu drop-in, zero-config i zero-dependencies dla powyższego przypadku użycia, wypróbuj pace.js ( http://github.hubspot.com/pace/docs/welcome/ ).

Automatycznie podłącza się do zdarzeń (ajax, readyState, historia pushstate, pętla zdarzeń js itp.) I pokazuje konfigurowalny program ładujący.

Działał dobrze z naszymi projektami reagowania / przekazywania (obsługuje zmiany nawigacji za pomocą routera reagowania, żądań przekaźników) (nie jest powiązany; używał pace.js w naszych projektach i działał świetnie)

Hafiz Ismail
źródło
Hej! Czy możesz mi powiedzieć, jak go używać z reakcją?
uneet7
wystarczy dołączyć skrypt do public/index.htmli wybrać styl. to jest martwa prosta, niesamowita wtyczka. Dziękuję Ci.
PJ3
Bez tej odpowiedzi nie znalazłbym tempa. To było tak łatwe do dołączenia, a przy odrobinie magii CSS i niektórych załącznikach do wydarzeń udało mi się zablokować / wyłączyć aplikację podczas przejść i dostosować spinner.
invertedSpear
12

Kiedy Twoja aplikacja React jest ogromna, jej uruchomienie i uruchomienie po załadowaniu strony zajmuje naprawdę dużo czasu. Powiedzmy, że montujesz część React aplikacji do #app. Zwykle ten element w pliku index.html to po prostu pusty element div:

<div id="app"></div>

Zamiast tego możesz umieścić trochę stylizacji i kilka obrazów, aby wyglądało lepiej między załadowaniem strony a początkowym renderowaniem aplikacji React do 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>

Po załadowaniu strony użytkownik natychmiast zobaczy oryginalną zawartość index.html. Wkrótce, gdy React będzie gotowy do zamontowania całej hierarchii renderowanych komponentów do tego węzła DOM, użytkownik zobaczy rzeczywistą aplikację.

Uwaga class, nie className. To dlatego, że musisz umieścić to w swoim pliku html.


Jeśli używasz SSR, sprawy są mniej skomplikowane, ponieważ użytkownik faktycznie zobaczy prawdziwą aplikację zaraz po załadowaniu strony.

rishat
źródło
To działa również mam dwa miejsca, w których odbywa się ładowanie. Jedna to ogromna aplikacja. a następnie jest przygotowanie (montaż różnych komponentów). Więc pojawia się migający krok, ponieważ app.render przejmuje kontrolę i animacja zostaje zresetowana ( naprawdę zastąpiona ). Czy byłby sposób, aby uniknąć tego flashowania? Czy React porówna DOM jeden do jednego? Ale z tego, co rozumiem, React dodaje do tagów wszelkiego rodzaju prywatne dane ...
Alexis Wilke,
12

Stanie się to zanim ReactDOM.render()przejmie kontrolę nad rootem <div> . Oznacza to, że Twoja aplikacja nie została zainstalowana do tego momentu.

Możesz więc dodać program ładujący do index.htmlpliku w katalogu głównym<div> . Będzie to widoczne na ekranie, dopóki React nie przejmie władzy.

Możesz użyć dowolnego elementu programu ładującego, który najlepiej Ci odpowiada ( svgna przykład z animacją).

Nie musisz go usuwać w żadnej metodzie cyklu życia. React zastąpi wszystkie elementy podrzędne swojego roota <div> renderowanym <App/>, jak widać na poniższym GIF-ie.

Przykład na CodeSandbox

wprowadź opis obrazu tutaj

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

Służy debuggerdo sprawdzania strony przed ReactDOM.render()uruchomieniem.

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);
cbdeveloper
źródło
piękne i eleganckie rozwiązanie
Gal Margalit
1
Cieszę się, że to pomaga!
cbdeveloper
9

Obecnie w React 16.8 możemy używać hooków:

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;
Max Kalik
źródło
5

Ustawienie limitu czasu w componentDidMount działa, ale w mojej aplikacji otrzymałem ostrzeżenie o wycieku pamięci. Spróbuj czegoś takiego.

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;
    }
  }
Rich Costello
źródło
4

Niedawno musiałem uporać się z tym problemem i znalazłem rozwiązanie, które dla mnie działa dobrze. Jednak próbowałem powyżej rozwiązania @Ori Drori i niestety nie działało to dobrze (miało pewne opóźnienia + nie podoba mi się użyciesetTimeout tam funkcji).

Oto, co wymyśliłem:

index.html plik

headTag wewnętrzny - style wskaźnika:

<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>

Teraz ten bodytag:

<div id="spinner" class="container">
  <div class="loading"></div>
</div>

<div id="app"></div>

Następnie pojawia się bardzo prosta logika, wewnątrz app.jspliku (w funkcji renderowania):

const spinner = document.getElementById('spinner');

if (spinner && !spinner.hasAttribute('hidden')) {
  spinner.setAttribute('hidden', 'true');
}

Jak to działa?

Kiedy pierwszy komponent (w mojej aplikacji jest tak samo app.jsw większości przypadków) zamontowany poprawnie, spinnerjest on ukrywany z zastosowaniem hiddendo niego atrybutu.

Co ważniejsze do dodania - !spinner.hasAttribute('hidden')warunek zapobiega dodawaniu hiddenatrybutu do błystki przy każdym montażu komponentu, więc w rzeczywistości zostanie dodany tylko raz, gdy cała aplikacja się załaduje.

miły użytkownik
źródło
4

Używam React-Progress-2 pakietu NPM React , który jest zależny od zera i działa świetnie w ReactJS.

https://github.com/milworm/react-progress-2

Instalacja:

npm install react-progress-2

Dołącz do swojego projektu react-progress-2 / main.css.

import "node_modules/react-progress-2/main.css";

Uwzględnij react-progress-2i umieść gdzieś w górnym komponencie, na przykład:

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>
        );
    }
});

Teraz, gdy chcesz pokazać wskaźnik, po prostu zadzwoń Progress.show(), na przykład:

loadFeed: function() {
    Progress.show();
    // do your ajax thing.
},

onLoadFeedCallback: function() {
    Progress.hide();
    // render feed.
}

Zwróć uwagę, że showi hidewywołania są ułożone w stos, więc po n-kolejnych wywołaniach show, musisz wykonać n hide wywołań, aby ukryć wskaźnik lub możesz użyć Progress.hideAll().

Alex Zavrazhniy
źródło
4

Używam również Reacta w mojej aplikacji. W przypadku żądań używam przechwytywaczy axios, więc świetnym sposobem na utworzenie ekranu modułu ładującego (na całej stronie, jak pokazano na przykładzie) jest dodanie klasy lub identyfikatora do na przykład body inside przechwytywacze (tutaj kod z oficjalnej dokumentacji z niestandardowym kodem):

// 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);
  }); 

A potem po prostu zaimplementuj w CSS swój moduł ładujący z pseudoelementami (lub dodaj klasę lub identyfikator do innego elementu, a nie body, jak chcesz) - możesz ustawić kolor tła na nieprzezroczysty lub przezroczysty, itp ... Przykład:

custom-loader:before {
    background: #000000;
    content: "";
    position: fixed;
    ...
}

custom-loader:after {
    background: #000000;
    content: "Loading content...";
    position: fixed;
    color: white;
    ...
}
adrian95999
źródło
3

Edytuj lokalizację pliku index.html w folderze publicznym . Skopiuj obraz do tej samej lokalizacji co plik index.html w folderze publicznym. A następnie zamień część zawartości index.html zawierającą <div id="root"> </div>tagi na poniższy kod 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>

Logo będzie się teraz pojawiać na środku strony podczas procesu ładowania. Po kilku sekundach zostanie zastąpiony przez React.

Magnus Melwin
źródło
2

Nie potrzebujesz tyle wysiłku, oto podstawowy przykład.

<!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>

Możesz bawić się HTMLi CSSsprawić, by wyglądał jak twój przykład.

Ahmed Kamal
źródło
1

Najważniejsze pytanie brzmi: co rozumiesz przez „ładowanie”? Jeśli mówisz o montowanym elemencie fizycznym, niektóre z pierwszych odpowiedzi są świetne. Jeśli jednak pierwsza rzecz, jaką wykonuje aplikacja, to sprawdzenie uwierzytelnienia, tak naprawdę ładujesz dane z zaplecza, czy użytkownik przekazał plik cookie oznaczający go jako autoryzowanego lub nieautoryzowanego użytkownika.

Opiera się to na reduksie, ale można go łatwo zmienić na zwykły model stanu reakcji.

twórca akcji:

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
      });
    }
  };
};

Ostatnia część oznacza, czy użytkownik jest autoryzowany, czy nie, ekran ładowania znika po otrzymaniu odpowiedzi.

Oto jak mógłby wyglądać komponent, który go ładuje:

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();
 }

}

Jeśli state.loading jest prawdą, zawsze zobaczymy ekran ładowania. Na componentDidMount wywołujemy naszą funkcję getTodos, która jest twórcą akcji, która zmienia stan. Ładowanie fałszywie, gdy otrzymamy odpowiedź (co może być błędem). Nasz komponent aktualizuje się, wywołania renderują się ponownie i tym razem nie ma ekranu ładowania z powodu instrukcji if.

user3605834
źródło
1

Uruchomienie aplikacji React opiera się na pobraniu głównego pakietu. Aplikacja React uruchamia się dopiero po pobraniu głównego pakietu w przeglądarce. Dzieje się tak nawet w przypadku leniwej architektury ładowania. Ale faktem jest, że nie możemy dokładnie określić nazwy żadnego pakietu. Ponieważ pakiet webpack doda wartość skrótu na końcu każdego pakietu w momencie uruchomienia polecenia „npm run build”. Oczywiście możemy tego uniknąć, zmieniając ustawienia skrótu, ale poważnie wpłynie to na problem z danymi pamięci podręcznej w przeglądarce. Przeglądarki mogą nie przyjąć nowej wersji z powodu tej samej nazwy pakietu. . potrzebujemy podejścia webpack + js + CSS, aby poradzić sobie z tą sytuacją.

zmień plik public / index.html jak poniżej

<!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>

W konfiguracji paczki produkcyjnej zmień opcję HtmlWebpackPlugin na poniżej

 new HtmlWebpackPlugin({
          inject: false,
...

Może być konieczne użycie polecenia „eject”, aby pobrać plik konfiguracyjny. Najnowszy pakiet internetowy może mieć opcję konfiguracji HtmlWebpackPlugin bez wysuwania projektu. wprowadź opis obrazu tutaj

Anoop Chillayi Kochappu
źródło
1

Użyłem również odpowiedzi @Ori Drori i udało mi się to uruchomić. Wraz z rozrastaniem się kodu Reacta, skompilowane pakiety będą musiały być pobierane przez przeglądarkę klienta przy pierwszym dostępie. Powoduje to problem z wygodą użytkownika, jeśli nie poradzisz sobie z tym dobrze.

To, co dodałem do odpowiedzi @Ori, to dodanie i wykonanie funkcji onload w index.html atrybucie onload tagu body, aby moduł ładujący zniknął po całkowitym załadowaniu wszystkiego w przeglądarce, zobacz poniższy fragment:

<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>
Joseph Tabajjwa
źródło
1

A co z używaniem Pace

Użyj tego adresu łącza tutaj.

https://github.hubspot.com/pace/docs/welcome/

1. Na ich stronie internetowej wybierz żądany styl i wklej w index.css

2. przejdź do cdnjs Skopiuj link do Pace Js i dodaj do swoich skryptów tagi w public / index.html

3. Automatycznie wykrywa obciążenia internetowe i wyświetla tempo na górze przeglądarki.

Możesz także zmienić wysokość i animację w css.

roqkabel
źródło
Niesamowite i można je błyskawicznie zintegrować.
UzumakiL