这是来自 Google Adsense 应用程序页面的示例。在主页显示之后显示的加载屏幕。
我不知道如何用 React 做同样的事情,因为如果我让 React 组件渲染加载屏幕,它不会在页面加载时显示,因为它必须等待之前渲染的 DOM。
更新:
我通过将屏幕加载程序放入 index.html
并在 React componentDidMount()
生命周期方法中删除它来举例说明我的方法。
原文由 Thanh Nguyen 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是来自 Google Adsense 应用程序页面的示例。在主页显示之后显示的加载屏幕。
我不知道如何用 React 做同样的事情,因为如果我让 React 组件渲染加载屏幕,它不会在页面加载时显示,因为它必须等待之前渲染的 DOM。
更新:
我通过将屏幕加载程序放入 index.html
并在 React componentDidMount()
生命周期方法中删除它来举例说明我的方法。
原文由 Thanh Nguyen 发布,翻译遵循 CC BY-SA 4.0 许可协议
当呈现 html 页面时,立即显示一个微调器(当 React 加载时),并在 React 准备好后隐藏它。
由于微调器是用纯 HTML/CSS 呈现的(在 React 域之外),React 不应该直接控制显示/隐藏过程,并且实现对 React 应该是透明的。
由于您将反应渲染到 DOM 容器中 - <div id="app"></div>
,您可以向该容器添加一个微调器,当反应加载和渲染时,微调器将消失。
您不能在反应根内添加 DOM 元素(例如 div),因为一旦调用 ReactDOM.render()
,反应将替换容器的内容。即使您呈现 null
,内容仍会被注释替换 - <!-- react-empty: 1 -->
。这意味着如果您想在主要组件挂载时显示加载器,数据正在加载,但实际上没有呈现任何内容,则放置在容器内的加载器标记(例如 <div id="app"><div class="loader"></div></div>
)将不起作用。
解决方法是将微调器类添加到反应容器,并使用 :empty
伪类。只要容器中没有渲染任何内容,微调器就会可见(注释不算数)。一旦 React 渲染了评论以外的东西,加载器就会消失。
示例 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>
要对微调器显示状态进行更细粒度的控制,请创建两个函数 showSpinner
和 hideSpinner
,并通过道具将它们传递给根容器。这些函数可以操纵 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>
原文由 Ori Drori 发布,翻译遵循 CC BY-SA 4.0 许可协议
这可以通过将加载图标放置在您的 html 文件中来完成(例如
index.html
),以便用户在加载 html 文件后立即看到该图标。当您的应用程序完成加载时,您可以简单地在生命周期挂钩中删除该加载图标,我通常在
componentDidMount
中这样做。