Ceci est un exemple tiré de la page d’application Google Adsense. L’écran de chargement affiché avant la page principale s’affiche après.
Je ne sais pas comment faire la même chose avec React, car si l'écran de chargement est rendu par le composant React, il ne s'affiche pas pendant le chargement de la page, car il doit attendre pour DOM rendu avant.
Mis à jour :
J'ai fait un exemple de mon approche en mettant le chargeur d'écran dans index.html
et le supprimant dans la méthode React componentDidMount()
.
Cela pourrait être fait en plaçant l'icône de chargement dans votre fichier html (index.html par exemple), afin que les utilisateurs la voient immédiatement après le chargement du fichier html.
Lorsque le chargement de votre application est terminé, vous pouvez simplement supprimer cette icône de chargement dans un crochet de cycle de vie, ce que je fais généralement dans componentDidMount
.
Lorsque la page html est restituée, affichez immédiatement une roulette (tandis que React se charge) et masquez-la une fois que React est prêt.
Puisque le spinner est rendu en HTML/CSS pur (en dehors du domaine React _), React ne doit pas contrôler directement le processus d'affichage/de masquage et l'implémentation doit être transparente pour React. .
Dans la mesure où vous effectuez le rendu dans un conteneur DOM - _<div id="app"></div>
_, vous pouvez ajouter un filtre à ce conteneur et, lorsque Rea va se charger et générer un rendu, le filtre disparaîtra.
Vous ne pouvez pas ajouter d'élément DOM (un div par exemple) à la racine de réaction, car React remplacera le contenu du conteneur dès que ReactDOM.render()
sera appelé. Même si vous rendez null
, le contenu sera toujours remplacé par un commentaire - _<!-- react-empty: 1 -->
_. Cela signifie que si vous souhaitez afficher le chargeur pendant le montage du composant principal, le chargement des données est en cours, mais rien n'est rendu, un marquage de chargeur placé à l'intérieur du conteneur (_<div id="app"><div class="loader"></div></div>
_ par exemple) ne fonctionnerait pas.
Une solution de contournement consiste à ajouter la classe spinner au conteneur de réactions et à utiliser la pseudo-classe :empty
. Le compteur sera visible tant que rien ne sera rendu dans le conteneur (les commentaires ne comptent pas). Dès que réagit rend autre chose qu'un commentaire, le chargeur disparaîtra.
Exemple 1
Dans l'exemple, vous pouvez voir un composant qui rend null
jusqu'à ce qu'il soit prêt. Le conteneur est également le chargeur - _<div id="app" class="app"></div>
_, et la classe du chargeur ne fonctionnera que si c'est _:empty
_ (voir les commentaires dans le code):
_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 -->
_
Exemple 2
Une variante de l’utilisation de la pseudo-classe _:empty
_ pour afficher/masquer un sélecteur définit le compteur en tant qu’élément frère du conteneur app et l’affiche tant que le conteneur est vide à l’aide de combinateur frère/sœur adjacent (_+
_):
_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>
_
Pour avoir un contrôle plus fin sur l’affichage des fileuses, créez deux fonctions showSpinner
et hideSpinner
et transmettez-les au conteneur racine via les accessoires. Les fonctions peuvent manipuler le DOM ou faire tout ce qui est nécessaire pour contrôler le disque. De cette manière, React ne connaît pas le "monde extérieur" et n'a pas besoin de contrôler directement le DOM. Vous pouvez facilement remplacer les fonctions à des fins de test ou si vous devez modifier la logique et les transmettre à d'autres composants de l'arborescence React.
Exemple 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>
_
Exemple 2 - crochets
Cet exemple utilise le crochet useEffect
pour masquer le compteur après le montage du composant.
_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>
_
La solution de contournement est la suivante:
Dans votre fonction de rendu, faites quelque chose comme ça:
constructor() {
this.state = { isLoading: true }
}
componentDidMount() {
this.setState({isLoading: false})
}
render() {
return(
this.state.isLoading ? *showLoadingScreen* : *yourPage()*
)
}
Initialiser isLoading avec true dans le constructeur et false sur composantDidMount
Si vous recherchez une bibliothèque en accès direct, zéro configuration et zéro dépendances pour le cas d'utilisation ci-dessus, essayez pace.js ( http://github.hubspot.com/pace/docs/welcome/ ).
Il se connecte automatiquement aux événements (ajax, readyState, historique pushstate, boucle d'événements js, etc.) et affiche un chargeur personnalisable.
Nous avons bien travaillé avec nos projets react/relay (gère les modifications de navigation à l’aide de react-router, demandes de relais) (Non associé; ayant utilisé pace.js pour nos projets, cela a très bien fonctionné)
Lorsque votre application React est massive, il faut vraiment du temps pour qu'elle soit opérationnelle une fois la page chargée. Disons que vous montez votre React partie de l'application sur #app
. Généralement, cet élément de votre index.html est simplement un div vide:
<div id="app"></div>
Ce que vous pouvez faire à la place, c’est de mettre un peu de style et un tas d’images pour que l’apparence soit meilleure entre le chargement de la page et le rendu initial de React app vers 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>
Une fois la page chargée, l’utilisateur verra immédiatement le contenu original de index.html. Peu de temps après, lorsque React est prêt à monter toute la hiérarchie des composants rendus sur ce nœud DOM, l'utilisateur verra l'application réelle.
Remarque class
, pas className
. C'est parce que vous devez mettre cela dans votre fichier html.
Si vous utilisez SSR, les choses sont moins compliquées, car l'utilisateur verra l'application réelle juste après le chargement de la page.
Cela se produira avant que ReactDOM.render()
ne prenne le contrôle de la racine <div>
. C'est à dire. votre application n'aura pas été montée jusqu'à ce point.
Vous pouvez donc ajouter votre chargeur dans votre fichier index.html
à la racine <div>
. Et cela sera visible à l'écran jusqu'à ce que React prenne le relais.
Vous pouvez utiliser l'élément de chargeur qui vous convient le mieux (svg
avec animation par exemple).
Vous n'avez pas besoin de le supprimer dans aucune méthode de cycle de vie. React remplacera tous les enfants de sa racine <div>
par votre rendu <App/>
, comme on peut le voir dans le GIF ci-dessous.
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
Utilisation de debugger
pour inspecter la page avant que ReactDOM.render()
ne soit exécuté.
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);
J'utilise aussi React dans mon application. Pour les requêtes, j'utilise des intercepteurs axios. Le meilleur moyen de créer un écran de chargement (une page entière comme vous avez montré un exemple) consiste à ajouter une classe ou un id à, par exemple, le corps à l'intérieur d'intercepteurs (ici le code de la documentation officielle avec un code personnalisé):
// 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);
});
Et ensuite, implémentez simplement en CSS votre chargeur avec des pseudo-éléments (ou ajoutez une classe ou un id à un élément différent, pas le corps à votre guise) - vous pouvez définir la couleur de l'arrière-plan sur opaque ou transparent, etc. Exemple:
custom-loader:before {
background: #000000;
content: "";
position: fixed;
...
}
custom-loader:after {
background: #000000;
content: "Loading content...";
position: fixed;
color: white;
...
}
De nos jours, nous pouvons aussi utiliser des hooks dans 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;
J'utilise le package react-progress-2 npm, qui est dépendant de zéro et qui fonctionne très bien dans ReactJS.
https://github.com/milworm/react-progress-2
Installation:
npm install react-progress-2
Ajoutez react-progress-2/main.css à votre projet.
import "node_modules/react-progress-2/main.css";
Incluez react-progress-2
et mettez-le quelque part dans le composant principal, par exemple:
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>
);
}
});
Maintenant, chaque fois que vous devez afficher un indicateur, appelez simplement Progress.show()
, par exemple:
loadFeed: function() {
Progress.show();
// do your ajax thing.
},
onLoadFeedCallback: function() {
Progress.hide();
// render feed.
}
Veuillez noter que les appels show
et hide
sont empilés. Ainsi, après n appels consécutifs, vous devez masquer les appels pour masquer un indicateur ou vous pouvez utiliser Progress.hideAll()
.
La définition du délai d'attente dans composantDidMount fonctionne, mais dans mon application, un avertissement de fuite de mémoire a été reçu. Essayez quelque chose comme ça.
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;
}
}
Récemment, j’ai dû faire face à ce problème et proposer une solution qui me convient parfaitement. Cependant, j'ai essayé la solution @Ori Drori ci-dessus et, malheureusement, cela n'a pas fonctionné correctement (avec quelques retards + je n'aime pas l'utilisation de la fonction setTimeout
).
Fichier index.html
Insidehead
tag - styles pour l'indicateur:
<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>
Maintenant la balise body
:
<div id="spinner" class="container">
<div class="loading"></div>
</div>
<div id="app"></div>
Et ensuite vient une logique très simple, à l'intérieur du fichier app.js
(dans la fonction de rendu):
const spinner = document.getElementById('spinner');
if (spinner && !spinner.hasAttribute('hidden')) {
spinner.setAttribute('hidden', 'true');
}
Comment ça marche?
Lorsque le premier composant (dans mon application, c'est app.js
ainsi que dans la plupart des cas) est monté correctement, la spinner
est masquée avec l'application de l'attribut hidden
.
Quoi de plus important d'ajouter - !spinner.hasAttribute('hidden')
, la condition empêche d'ajouter l'attribut hidden
à la roulette à chaque montage de composant; il ne sera donc ajouté qu'une seule fois, lors du chargement complet de l'application.
Modifiez l’emplacement de votre fichier index.html dans le dossier public . Copiez votre image au même emplacement que index.html dans un dossier public. Et puis remplacez la partie du contenu de index.html contenant les balises <div id="root"> </div>
par le code html indiqué ci-dessous.
<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>
Le logo apparaîtra au milieu de la page pendant le processus de chargement. Et sera alors remplacé après quelques secondes par React.
Le démarrage de react app est basé sur le téléchargement du bundle principal. L'application React ne démarre qu'après le téléchargement de l'ensemble principal dans le navigateur. Ceci est même vrai en cas d'architecture de chargement paresseux. Mais le fait est que nous ne pouvons pas préciser le nom d’un paquet. Parce que webapck ajoutera une valeur de hachage à la fin de chaque ensemble au moment où vous exécuterez la commande 'npm run build'. Bien sûr, nous pouvons éviter cela en modifiant les paramètres de hachage, mais cela affectera sérieusement le problème des données de cache dans le navigateur. Les navigateurs risquent de ne pas utiliser la nouvelle version en raison du même nom d’ensemble. . nous avons besoin d’une approche webpack + js + CSS pour gérer cette situation.
changez le fichier public/index.html comme ci-dessous
<!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>
Dans votre configuration Webapack de production, modifiez l’option HtmlWebpackPlugin en dessous de
new HtmlWebpackPlugin({
inject: false,
...
Vous devrez peut-être utiliser la commande 'éjecter' pour obtenir le fichier de configuration. le dernier pack Web peut avoir la possibilité de configurer HtmlWebpackPlugin sans éjecter le projet.
Vous n'avez pas besoin de beaucoup d'effort, voici un exemple de base.
<!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>
Vous pouvez jouer avec HTML
et CSS
pour que cela ressemble à votre exemple.
La question la plus importante est: qu'entendez-vous par "chargement"? Si vous parlez de l'élément physique en cours de montage, certaines des premières réponses sont excellentes. Cependant, si la première chose que fait votre application est de vérifier l'authentification, vous chargez en réalité des données du backend, que l'utilisateur ait ou non transmis un cookie qui les identifie comme un utilisateur autorisé ou non.
Ceci est basé sur redux, mais vous pouvez facilement le changer en modèle d'état simple.
créateur d'action:
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
});
}
};
};
La dernière partie signifie que l'utilisateur soit autorisé ou non, l'écran de chargement disparaît après la réception d'une réponse.
Voici à quoi pourrait ressembler un composant qui le charge:
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();
}
}
Si state.loading est la vérité, nous verrons toujours un écran de chargement. Sur composantDidMount, nous appelons notre fonction getTodos, qui est un créateur d'action qui transforme state.loading falsy lorsque nous obtenons une réponse (ce qui peut être une erreur). Notre composant est mis à jour, les appels sont rendus à nouveau et cette fois, il n'y a pas d'écran de chargement en raison de l'instruction if.