React - 在 DOM 渲染时显示加载屏幕?

IT技术 reactjs asynchronous redux react-dom
2021-03-28 02:57:23

这是来自 Google Adsense 应用程序页面的示例。显示在主页之前的加载屏幕显示在之后。

在此处输入图片说明

我不知道如何用 React 做同样的事情,因为如果我让 React 组件呈现加载屏幕,它在页面加载时不会显示,因为它必须等待之前呈现的 DOM。

更新

我通过将屏幕加载器放入index.html并在 ReactcomponentDidMount()生命周期方法中删除它来举例说明我的方法。

示例react-loading-screen

6个回答

目标

当 html 页面被渲染时,立即显示一个微调器(在 React 加载时),并在 React 准备好后隐藏它。

由于微调器是在纯 HTML/CSS 中呈现的(在 React 域之外),因此 React 不应该直接控制显示/隐藏过程,并且实现应该对 React 透明。

解决方案 1 - :empty 伪类

由于您将 react 渲染到 DOM 容器 - 中<div id="app"></div>,您可以向该容器添加一个微调器,当 react 加载和渲染时,微调器将消失。

你不能在 react 根中添加 DOM 元素(例如一个 div),因为 React 会在ReactDOM.render()被调用后立即替换容器的内容即使您进行渲染null,内容仍会被注释替换 - <!-- react-empty: 1 -->这意味着如果你想在主要组件挂载时显示加载器,数据正在加载,但实际上没有渲染任何东西,放置在容器内的加载器标记(<div id="app"><div class="loader"></div></div>例如)将不起作用。

一种解决方法是将微调器类添加到react容器中,并使用:empty伪类只要容器中没有渲染任何内容,微调器就会可见(评论不算数)。一旦 react 渲染了评论以外的东西,加载器就会消失。

示例 1

在示例中,您可以看到一个组件null在准备就绪之前一直渲染容器也是加载器 - <div id="app" class="app"></div>,加载器的类只有在它是:empty(参见代码中的注释)时才会工作

示例 2

使用:empty伪类显示/隐藏选择器的一种变体是将微调器设置为应用程序容器的同级元素,并在容器为空时使用相邻的同级组合器( +)显示它


解决方案 2 - 将微调器“处理程序”作为props传递

要对微调器显示状态进行更细粒度的控制,请创建两个函数showSpinnerand hideSpinner,并通过 props 将它们传递给根容器。这些函数可以操作 DOM,或者做任何需要控制微调器的事情。这样,React 就不会意识到“外部世界”,也不需要直接控制 DOM。您可以轻松替换测试的函数,或者如果您需要更改逻辑,您可以将它们传递给 React 树中的其他组件。

示例 1

示例 2 - 钩子

此示例使用useEffect钩子在组件安装后隐藏微调器。

第二个是CSS。我使用了全局 CSS,但您可以在 JS 中使用 CSS Modules 或 CSS。第三个是 HTML 文件,如果需要,它可能包含微调器标记(第二个示例)。
2021-05-24 02:57:23
return null添加评论,它将呈现为一个空白屏幕。:empty 伪类与return null一起工作,因为它在确定容器是否为空时忽略注释。
2021-06-02 02:57:23
@dryleaf - setTimeout 不是解决方案的一部分。它模拟在呈现内容之前等待异步操作。
2021-06-03 02:57:23
你能澄清最后两个代码部分应该在哪里吗?第一个显然在 react 组件的 javascript src 文件中,我猜第三个在 html 模板中,由所述 js 文件呈现,但是第二个去哪里了?
2021-06-11 02:57:23
@hamza-jutt - 你应该就此提出一个新问题。
2021-06-21 02:57:23

这可以通过将加载图标放在您的 html 文件(例如 index.html)中来完成,以便用户在加载 html 文件后立即看到该图标。

当您的应用程序完成加载时,您可以简单地在生命周期挂钩中删除该加载图标,我通常在componentDidMount.

这对 PWA 有什么不利之处吗?它会干扰默认的启动画面吗?
2021-05-26 02:57:23
@benmneb 有干扰吗?
2021-05-31 02:57:23
如果您将根组件挂载到该图标的父节点,则甚至无需手动删除它。React 将清理 mount 节点的子节点,并将其自己新渲染的 DOM 放在那里。
2021-06-10 02:57:23
我没有把图标放在 React 应用程序的根节点内,只是我觉得不合适
2021-06-18 02:57:23

解决方法是:

在你的渲染函数中做这样的事情:

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

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

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

在构造函数中将 isLoading 初始化为 true,在 componentDidMount 上将其初始化为 false

我必须在所有页面中执行此操作还是仅在应用程序条目中执行此操作
2021-05-22 02:57:23
当我们调用 ajax 方法将数据加载到子组件时。在子组件数据填充之前调用 componentDidMount。我们如何克服这类问题?
2021-06-03 02:57:23
对于 Mounting Life cyle 很好,您想为更新生命周期添加一些东西吗?
2021-06-06 02:57:23

这将在ReactDOM.render()控制root 之前发生<div>即您的应用程序不会被安装到那个点。

因此,您可以将加载程序添加index.html到根目录中的文件中<div>这将在屏幕上可见,直到 React 接管。

您可以使用任何最适合您的加载器元素(svg例如动画)。

您不需要在任何生命周期方法中删除它。React 将用您的渲染替换其根的 任何子项,如下面的 GIF 所示。<div><App/>

CodeSandbox 上的示例

在此处输入图片说明

索引.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>

索引.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);
我很高兴它有帮助!
2021-05-26 02:57:23
一个美丽而优雅的解决方案
2021-05-29 02:57:23

如果有人正在为上述用例寻找插入式、零配置和零依赖库,请尝试 pace.js ( https://codebyzach.github.io/pace/docs/ )。

它自动挂钩事件(ajax、readyState、历史推送状态、js 事件循环等)并显示可定制的加载程序。

与我们的 react/relay 项目配合得很好(使用 react-router 处理导航更改,relay 请求) (不附属;已经在我们的项目中使用了 pace.js 并且效果很好)

只需将脚本附加到public/index.html并选择一种样式即可。这是一个非常简单、惊人的插件。谢谢。
2021-05-26 02:57:23
如果没有这个答案,我就找不到节奏。包含它非常容易,通过一些 CSS 魔法和一些事件附件,我能够在转换过程中阻止/禁用应用程序并自定义微调器。
2021-06-02 02:57:23
嘿!你能告诉我如何在 react 中使用它吗?
2021-06-13 02:57:23