这是一个来自谷歌Adsense应用页面的例子。加载界面显示在主界面之前。
我不知道如何用React做同样的事情,因为如果我用React组件渲染加载屏幕,它不会在页面加载时显示,因为它必须等待DOM渲染之前。
更新:
我通过将屏幕加载器放在index.html中并在React componentDidMount()生命周期方法中删除它来举例说明我的方法。
示例和反应加载屏幕。
这是一个来自谷歌Adsense应用页面的例子。加载界面显示在主界面之前。
我不知道如何用React做同样的事情,因为如果我用React组件渲染加载屏幕,它不会在页面加载时显示,因为它必须等待DOM渲染之前。
更新:
我通过将屏幕加载器放在index.html中并在React componentDidMount()生命周期方法中删除它来举例说明我的方法。
示例和反应加载屏幕。
当前回答
在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;
}
}
其他回答
如果有人正在为上述用例寻找一个插入式、零配置和零依赖的库,请尝试pace.js (https://codebyzach.github.io/pace/docs/)。
它自动挂钩事件(ajax, readyState,历史推送状态,js事件循环等),并显示一个可定制的加载器。
与我们的react/relay项目合作良好(使用react-router, relay请求处理导航更改) (不是affliated;在我们的项目中使用了pace.js,它工作得很好)
我们的目标
当html页面被渲染时,立即显示一个转轮(在React加载时),并在React准备好后隐藏它。
由于旋转器是在纯HTML/CSS中呈现的(在React域之外),React不应该直接控制显示/隐藏过程,实现对React应该是透明的。
解决方案1 -:empty伪类
因为你把react渲染到一个DOM容器中- <div id="app"></div>,你可以在这个容器中添加一个旋转器,当react加载并渲染时,旋转器将消失。
You can't add a DOM element (a div for example) inside the react root, since React will replace the contents of the container as soon as ReactDOM.render() is called. Even if you render null, the content would still be replaced by a comment - <!-- react-empty: 1 -->. This means that if you want to display the loader while the main component mounts, data is loading, but nothing is actually rendered, a loader markup placed inside the container (<div id="app"><div class="loader"></div></div> for example) would not work.
一个解决方法是将spinner类添加到react容器中,并使用:empty伪类。旋转器将是可见的,只要没有任何东西被呈现到容器中(注释不算数)。一旦react渲染了注释以外的东西,加载器就会消失。
示例1
在这个例子中,你可以看到一个组件在准备好之前呈现为空。容器也是加载器- <div id="app" class="app"></div>,并且加载器的类只有在它为:空时才会工作(见代码中的注释):
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伪类来显示/隐藏选择器的一种变体是将spinner设置为应用容器的兄弟元素,并且只要容器为空,就使用相邻的兄弟组合子(+)显示它:
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>
那么使用速度呢?
使用这里的链接地址。
https://github.hubspot.com/pace/docs/welcome/
1.在他们的网站上选择你想要的样式并粘贴在index.css中
2.复制Pace Js的链接并添加到public/index.html中的脚本标签中
3.它会自动检测网页负载,并在浏览器顶部显示速度。
你也可以在css中修改高度和动画。
在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;
}
}
这将发生在ReactDOM.render()控制根目录<div>之前。也就是说,你的应用程序到那时还没有被安装。
所以你可以把你的加载器添加到index.html文件的根目录<div>。在React接管之前,这将在屏幕上可见。
您可以使用任何最适合您的加载器元素(例如带有动画的svg)。
您不需要在任何生命周期方法上删除它。React会用你渲染的<App/>替换它的根<div>的所有子元素,就像我们在下面的动图中看到的那样。
关于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
在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);