ตอบสนอง - แสดงหน้าจอโหลดขณะที่ DOM กำลังเรนเดอร์?


150

นี่คือตัวอย่างจากหน้าแอปพลิเคชัน Google Adsense หน้าจอโหลดปรากฏขึ้นก่อนหน้าหลักแสดงให้เห็นหลังจาก

ป้อนคำอธิบายรูปภาพที่นี่

ฉันไม่ทราบวิธีการทำสิ่งเดียวกันกับ React เพราะถ้าฉันทำการโหลดหน้าจอที่เรนเดอร์ด้วยองค์ประกอบ React มันจะไม่แสดงในขณะที่หน้ากำลังโหลดเพราะมันต้องรอ DOM ที่เรนเดอร์มาก่อน

อัปเดต :

ฉันทำตัวอย่างของวิธีการของฉันโดยใส่ตัวโหลดหน้าจอindex.htmlและลบออกในcomponentDidMount()วิธีวงจรชีวิตของReact

ตัวอย่างและการตอบสนองในการโหลดหน้าจอ


แสดงสิ่งที่คุณต้องการแสดงใน js ธรรมดาจากนั้นซ่อนไว้หรือลบออกจาก DOM เมื่อการตอบสนองติดตั้งแล้ว สิ่งที่คุณต้องทำคือการซ่อนจากรหัสการตอบสนอง
FurkanO

มันยอดเยี่ยมมาก! ขอบคุณ.
Arman Karimi

คำตอบ:


101

สิ่งนี้สามารถทำได้โดยการวางไอคอนการโหลดในไฟล์ html ของคุณ (index.html สำหรับอดีต) เพื่อให้ผู้ใช้เห็นไอคอนทันทีหลังจากโหลดไฟล์ html

componentDidMountเมื่อแอปของคุณโหลดเสร็จคุณก็สามารถลบที่ไอคอนการโหลดในเบ็ดวงจรชีวิตผมมักจะทำใน


11
หากคุณติดตั้งองค์ประกอบรูทกับโหนดพาเรนต์ของไอคอนนั้นคุณไม่จำเป็นต้องลบมันออกด้วยตนเอง ปฏิกิริยาจะทำความสะอาดลูกของโหนดการเชื่อมต่อและใส่ DOM ที่แสดงผลใหม่ของตัวเองที่นั่นแทน
rishat

6
ฉันไม่ได้ใส่ไอคอนไว้ในรูทโหนดของแอป React มันแค่รู้สึกไม่ถูกต้องสำหรับฉัน
kkkkkkk

172

เป้าหมาย

เมื่อหน้า html แสดงผลให้สปินเนอร์ทันที (ในขณะที่ React load) และซ่อนไว้หลังจาก React พร้อม

เนื่องจากสปินเนอร์แสดงผลในรูปแบบ HTML / CSS บริสุทธิ์ (นอกโดเมน React) การตอบสนองจึงไม่ควรควบคุมกระบวนการแสดง / ซ่อนโดยตรงและการใช้งานควรโปร่งใสต่อปฏิกิริยา

โซลูชันที่ 1 - the: คลาสหลอกว่าง

เมื่อคุณเรนเดอร์ปฏิกิริยาลงในคอนเทนเนอร์ DOM - <div id="app"></div>คุณสามารถเพิ่มสปินเนอร์ในคอนเทนเนอร์นั้นและเมื่อปฏิกิริยาจะโหลดและแสดงผลสปินเนอร์จะหายไป

คุณไม่สามารถเพิ่มองค์ประกอบ DOM (ตัวอย่างเช่น div) ในรูทการตอบสนองเนื่องจาก React จะแทนที่เนื้อหาของคอนเทนเนอร์ทันทีที่ReactDOM.render()ถูกเรียก แม้ว่าคุณจะทำให้nullเนื้อหาจะยังคงถูกแทนที่ด้วยการแสดงความคิดเห็น <!-- react-empty: 1 -->- ซึ่งหมายความว่าหากคุณต้องการแสดงโหลดเดอร์ในขณะที่เมาท์ส่วนประกอบหลักกำลังโหลดข้อมูล แต่ไม่มีการแสดงผลใด ๆ มาร์กอัปโหลดเดอร์ที่วางไว้ในคอนเทนเนอร์ ( <div id="app"><div class="loader"></div></div>ตัวอย่าง) จะไม่ทำงาน

การแก้ปัญหาคือการเพิ่มระดับปั่นเพื่อตอบสนองภาชนะและใช้ระดับหลอก:empty สปินเนอร์จะปรากฏให้เห็นตราบใดที่ไม่มีการแสดงผลลงในคอนเทนเนอร์ (ความคิดเห็นจะไม่นับ) ทันทีที่ตอบกลับแสดงผลอย่างอื่นนอกจากความคิดเห็นตัวโหลดจะหายไป

ตัวอย่างที่ 1

ในตัวอย่างคุณสามารถเห็นส่วนประกอบที่แสดงผลnullจนกว่าจะพร้อม คอนเทนเนอร์เป็นตัวโหลดเช่นกัน - <div id="app" class="app"></div>และคลาสของตัวโหลดจะใช้ได้ก็ต่อเมื่อมัน:empty(ดูความคิดเห็นในโค้ด):

ตัวอย่างที่ 2

รูปแบบการใช้:emptyคลาสหลอกเพื่อแสดง / ซ่อนตัวเลือกคือการตั้งค่าสปินเนอร์เป็นองค์ประกอบพี่น้องไปยังคอนเทนเนอร์ของแอปและแสดงตราบใดที่คอนเทนเนอร์ว่างเปล่าโดยใช้combinator sibling ที่อยู่ติดกัน ( +):


โซลูชันที่ 2 - ส่ง "ตัวจัดการ" สปินเนอร์เป็นอุปกรณ์ประกอบฉาก

หากต้องการให้มีการควบคุมอย่างละเอียดยิ่งขึ้นเกี่ยวกับสถานะการแสดงผลของสปินเนอร์ให้สร้างสองฟังก์ชันshowSpinnerและhideSpinnerและส่งไปยังรูทคอนเทนเนอร์ผ่านอุปกรณ์ประกอบฉาก ฟังก์ชั่นสามารถจัดการ DOM หรือทำสิ่งที่จำเป็นเพื่อควบคุมสปินเนอร์ ด้วยวิธีนี้การตอบสนองไม่ได้ตระหนักถึง "โลกภายนอก" และไม่จำเป็นต้องควบคุม DOM โดยตรง คุณสามารถแทนที่ฟังก์ชั่นสำหรับการทดสอบได้อย่างง่ายดายหรือหากคุณต้องการเปลี่ยนลอจิกและคุณสามารถส่งพวกมันไปยังส่วนประกอบอื่น ๆ ในแผนผัง React

ตัวอย่างที่ 1

ตัวอย่างที่ 2 - hooks

ตัวอย่างนี้ใช้useEffectเบ็ดเพื่อซ่อนตัวหมุนหลังจากส่วนประกอบประกอบ


คุณช่วยอธิบายได้ไหมว่าส่วนรหัส 2 ตัวสุดท้ายควรอยู่ที่ไหน อย่างแรกคือชัดเจนในไฟล์ javascript src สำหรับองค์ประกอบการตอบสนองที่สามฉันคาดเดาไปในแม่แบบ html ที่จะแสดงผลโดยไฟล์ js กล่าว แต่ที่สองไปที่ไหน
levraininjaneer

1
ที่สองคือ CSS ฉันใช้ CSS ทั่วโลก แต่คุณสามารถใช้โมดูล CSS หรือ CSS ใน JS ที่สามคือไฟล์ HTML ซึ่งอาจรวมถึงมาร์กอัปปินเนอร์หากจำเป็น (ตัวอย่างที่ 2)
Ori Drori

การหมดเวลานั้นไม่ดีเมื่อพิจารณาถึงประสิทธิภาพ
dryleaf

4
@dryleaf - setTimeout ไม่ได้เป็นส่วนหนึ่งของโซลูชัน มันจำลองการรอการดำเนินการ async ก่อนที่จะแสดงผลเนื้อหา
Ori Drori

ฉันใช้วิธีการที่คล้ายกัน ฉันไม่พบสิ่งใดใน webpack ที่สามารถช่วยฉัน bust cache สำหรับไฟล์ css ที่ต้องการใช้กับโหลดเดอร์ คุณช่วยได้ไหม
hamza-jutt

40

วิธีแก้ปัญหาสำหรับสิ่งนี้คือ:

ในฟังก์ชั่นเรนเดอร์ของคุณทำสิ่งนี้:

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

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

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

เริ่มต้น isLoading เป็นจริงในตัวสร้างและเท็จบน componentDidMount


เมื่อเราเรียกวิธีการ ajax เพื่อโหลดข้อมูลไปยังองค์ประกอบลูก componentDidMount ถูกเรียกก่อนการเติมข้อมูลคอมโพเนนต์ลูก เราจะเอาชนะปัญหาประเภทนี้ได้อย่างไร
dush88c

2
สำหรับการติดตั้ง Life cyle ไม่เป็นไรคุณต้องการที่จะเพิ่มบางสิ่งสำหรับวงจรชีวิต updation
ซากิ

ฉันต้องทำสิ่งนี้ในทุกหน้าหรือเพียงแค่ในรายการแอพ
Pedro JR

16

หากใครที่กำลังมองหาไลบรารี่, zero-config และ zero-dependencies สำหรับกรณีการใช้งานข้างต้นลองใช้ pace.js ( http://github.hubspot.com/pace/docs/welcome/ )

มันจะเชื่อมโยงกับกิจกรรมโดยอัตโนมัติ (Ajax, ReadyState, Pushstate ประวัติ, js Event Loop ฯลฯ ) และแสดงตัวโหลดที่ปรับแต่งได้

ทำงานได้ดีกับโครงการตอบสนอง / รีเลย์ของเรา (จัดการการเปลี่ยนแปลงการนำทางโดยใช้ react-router, คำขอรีเลย์) (ไม่ได้รับการรับรอง; ใช้ pace.js สำหรับโครงการของเราและทำงานได้ดี)


เฮ้! คุณสามารถบอกวิธีใช้กับปฏิกิริยาได้หรือไม่?
uneet7

เพียงแนบสคริปต์public/index.htmlและเลือกสไตล์ นี่เป็นปลั๊กอินที่เรียบง่ายและน่าทึ่ง ขอบคุณ.
PJ3

ฉันจะไม่ได้พบจังหวะโดยไม่ต้องคำตอบนี้ มันง่ายมากที่จะรวมและด้วย CSS มายากลเล็กน้อยและสิ่งที่แนบมากับเหตุการณ์บางอย่างฉันสามารถบล็อก / ปิดการใช้งานแอพในช่วงการเปลี่ยนภาพและปรับแต่งสปินเนอร์
invertedSpear

12

เมื่อแอป React ของคุณมีขนาดใหญ่ต้องใช้เวลาในการเริ่มต้นและเรียกใช้หลังจากโหลดหน้าเว็บแล้ว #appบอกว่าคุณติดของคุณตอบสนองส่วนหนึ่งของการตรวจสอบเพื่อ โดยปกติแล้วองค์ประกอบนี้ใน index.html ของคุณเป็นเพียง div ว่างเปล่า:

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

สิ่งที่คุณสามารถทำได้คือใส่สไตล์และรูปภาพจำนวนมากเพื่อทำให้ดูดีขึ้นระหว่างการโหลดหน้าเว็บและแอป React เริ่มต้นที่แสดงผลไปยัง 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>

หลังจากโหลดหน้าเว็บแล้วผู้ใช้จะเห็นเนื้อหาต้นฉบับของ index.html ทันที หลังจากนั้นไม่นานเมื่อ React พร้อมที่จะเมานต์ลำดับชั้นทั้งหมดของคอมโพเนนต์ที่แสดงผลไปยังโหนด DOM นี้ผู้ใช้จะเห็นแอปจริง

หมายเหตุไม่class classNameเป็นเพราะคุณต้องใส่สิ่งนี้ลงในไฟล์ html ของคุณ


หากคุณใช้ SSR สิ่งต่าง ๆ มีความซับซ้อนน้อยกว่าเพราะผู้ใช้จะเห็นแอปจริงทันทีที่โหลดหน้าเว็บ


ใช้งานได้ฉันมีสองที่ที่การโหลดเกิดขึ้น หนึ่งคือแอปขนาดใหญ่ และต่อไปคือการเตรียมการ (ติดตั้งส่วนประกอบต่าง ๆ ) ดังนั้นฉันจึงได้รับขั้นตอนกระพริบเพราะแอพผู้สร้างใช้เวลานานและภาพเคลื่อนไหวจะถูกรีเซ็ต ( แทนที่จริงๆ) มีวิธีที่จะหลีกเลี่ยงแฟลชนั้นหรือไม่ ปฏิกิริยาจะเปรียบเทียบ DOM หนึ่งกับหนึ่งหรือไม่ แต่จากสิ่งที่ฉันเข้าใจ React เพิ่มข้อมูลส่วนตัวทุกประเภทไว้ในแท็ก ...
Alexis Wilke

12

สิ่งนี้จะเกิดขึ้นก่อนที่ReactDOM.render()จะควบคุมรู <div>ท นั่นคือแอปของคุณจะไม่ถูกติดตั้งจนถึงจุดนั้น

ดังนั้นคุณสามารถเพิ่มตัวโหลดของคุณในindex.htmlไฟล์ภายในรูทได้<div>ได้ และจะปรากฏให้เห็นบนหน้าจอจนกว่า React จะเข้าครอบครอง

คุณสามารถใช้องค์ประกอบตัวโหลดที่ทำงานได้ดีที่สุดสำหรับคุณ ( svgเช่นภาพเคลื่อนไหว)

คุณไม่จำเป็นต้องลบออกในทุกช่วงอายุ React จะแทนที่ลูก ๆ ของroot <div>ด้วยการแสดงผลของคุณ<App/>ดังที่เราเห็นใน GIF ด้านล่าง

ตัวอย่างบน 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

ใช้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);

ทางออกที่สวยงามและสง่างาม
Gal Margalit

1
ฉันดีใจที่มันช่วยได้!
cbdeveloper

9

ทุกวันนี้เราสามารถใช้ hooks ได้ใน 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;

5

การตั้งค่าการหมดเวลาใน 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;
    }
  }

4

ฉันต้องจัดการกับปัญหานั้นเมื่อเร็ว ๆ นี้และหาวิธีแก้ปัญหาซึ่งใช้ได้ดีสำหรับฉัน อย่างไรก็ตามฉันได้ลอง @Ori Drori แล้ว แต่มันก็ใช้ไม่ได้ (มีความล่าช้าบ้าง + ฉันไม่ชอบการใช้งานของsetTimeoutฟังก์ชั่นที่นั่น)

นี่คือสิ่งที่ฉันมาด้วย:

index.html ไฟล์

headแท็กภายใน - สไตล์สำหรับตัวบ่งชี้:

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

ตอนนี้bodyแท็ก:

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

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

และจากนั้นตรรกะที่ง่ายมากคือapp.jsไฟล์ภายใน(ในฟังก์ชั่นการเรนเดอร์):

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

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

วิธีมันไม่ทำงาน?

เมื่อองค์ประกอบแรก (ในแอพของฉันเป็นapp.jsส่วนใหญ่เช่นกัน) เมาท์อย่างถูกต้องspinnerจะถูกซ่อนด้วยการใช้hiddenคุณสมบัติกับมัน

สิ่งที่สำคัญกว่าคือการเพิ่ม !spinner.hasAttribute('hidden')เงื่อนไขป้องกันการเพิ่มhiddenแอตทริบิวต์ไปยังสปินเนอร์ที่มีส่วนประกอบทั้งหมดดังนั้นจริง ๆ แล้วมันจะถูกเพิ่มเพียงครั้งเดียวเมื่อแอปทั้งหมดโหลด


4

ฉันใช้แพคเกจreact-progress-2 npm ซึ่งไม่ขึ้นกับศูนย์และทำงานได้ดีใน ReactJS

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

การติดตั้ง:

npm install react-progress-2

รวม react-progress-2 / main.css ไว้ในโครงการของคุณ

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

รวมreact-progress-2และวางไว้ที่ไหนสักแห่งในองค์ประกอบด้านบนตัวอย่างเช่น

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

ตอนนี้เมื่อใดก็ตามที่คุณต้องการแสดงตัวบ่งชี้เพียงแค่โทรProgress.show()ตัวอย่างเช่น:

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

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

โปรดทราบว่าshowและhideสายซ้อนกันแสดงโทรดังนั้นหลังจาก n-ติดต่อกันที่คุณต้องทำ n Progress.hideAll()ซ่อนโทรไปซ่อนตัวบ่งชี้หรือคุณสามารถใช้


4

ฉันใช้ React ในแอปของฉันด้วย สำหรับคำขอที่ฉันใช้ axios interceptors วิธีที่ยอดเยี่ยมในการสร้างหน้าจอตัวโหลด (เต็มหน้าจอตามที่คุณแสดงตัวอย่าง) คือการเพิ่ม class หรือ id ให้กับ body ตัวอย่างใน interceptors (นี่คือรหัสจากเอกสารอย่างเป็นทางการพร้อมรหัสที่กำหนดเอง):

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

และจากนั้นก็นำไปใช้ใน CSS โหลดเดอร์ของคุณด้วยองค์ประกอบหลอก (หรือเพิ่มคลาสหรือรหัสไปยังองค์ประกอบที่แตกต่างกันไม่ใช่ร่างกายตามที่คุณต้องการ) - คุณสามารถตั้งค่าสีของพื้นหลังเป็นทึบแสงหรือโปร่งใส ฯลฯ ... ตัวอย่าง:

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

custom-loader:after {
    background: #000000;
    content: "Loading content...";
    position: fixed;
    color: white;
    ...
}

3

แก้ไขตำแหน่งไฟล์ index.html ของคุณในโฟลเดอร์สาธารณะ คัดลอกรูปภาพของคุณไปยังตำแหน่งเดียวกับindex.htmlในโฟลเดอร์สาธารณะ จากนั้นแทนที่ส่วนของเนื้อหาของ index.html ที่มี <div id="root"> </div>แท็กเป็นรหัส 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>

โลโก้จะปรากฏที่ตรงกลางของหน้าระหว่างการโหลด และจะถูกแทนที่หลังจากนั้นสองสามวินาทีโดย React


2

คุณไม่ต้องการความพยายามมากขนาดนี้เป็นตัวอย่างพื้นฐาน

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

คุณสามารถเล่นกับHTMLและCSSเพื่อให้ดูเหมือนกับตัวอย่างของคุณ


1

คำถามที่สำคัญที่สุดคือ: คุณหมายถึงอะไรโดย 'โหลด'? หากคุณกำลังพูดถึงองค์ประกอบทางกายภาพที่ติดตั้งอยู่คำตอบแรก ๆ ที่นี่ยอดเยี่ยม อย่างไรก็ตามหากสิ่งแรกที่แอปของคุณทำการตรวจสอบความถูกต้องสิ่งที่คุณกำลังโหลดจริง ๆ คือข้อมูลจากแบ็กเอนด์ว่าผู้ใช้ผ่านคุกกี้ที่ติดป้ายชื่อพวกเขาเป็นผู้ใช้ที่ได้รับอนุญาตหรือไม่ได้รับอนุญาต

สิ่งนี้มีพื้นฐานมาจาก redux แต่คุณสามารถเปลี่ยนเป็นรูปแบบ state react ล้วนๆได้อย่างง่ายดาย

ผู้สร้างแอ็คชั่น:

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

ส่วนสุดท้ายหมายความว่าผู้ใช้จะถูกตรวจสอบหรือไม่หน้าจอโหลดจะหายไปหลังจากที่ได้รับการตอบสนอง

นี่คือองค์ประกอบที่สามารถโหลดได้:

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

}

หาก state.loading เป็นความจริงเราจะเห็นหน้าจอโหลดอยู่เสมอ บน componentDidMount เราเรียกใช้ฟังก์ชัน getTodos ซึ่งเป็นผู้สร้างแอ็คชั่นที่เปลี่ยน state.loading เท็จเมื่อเราได้รับการตอบกลับ (ซึ่งอาจเป็นข้อผิดพลาด) องค์ประกอบของเราอัปเดตแสดงการโทรอีกครั้งและในเวลานี้ไม่มีหน้าจอโหลดเนื่องจากคำสั่ง if


1

การเริ่มต้นแอพ react ขึ้นอยู่กับการดาวน์โหลดชุดบันเดิลหลัก แอป React จะเริ่มต้นหลังจากดาวน์โหลดบันเดิลหลักในเบราว์เซอร์เท่านั้น สิ่งนี้จะเป็นจริงในกรณีที่สถาปัตยกรรมแบบสันหลังยาว แต่ความจริงก็คือเราไม่สามารถระบุชื่อของบันเดิลใด ๆ ได้อย่างแน่นอน เนื่องจาก webpack จะเพิ่มค่าแฮชที่ส่วนท้ายของแต่ละบันเดิล ณ เวลาที่คุณรันคำสั่ง 'npm run build' แน่นอนว่าเราสามารถหลีกเลี่ยงปัญหานี้ได้โดยการเปลี่ยนการตั้งค่าแฮช แต่จะส่งผลกระทบอย่างรุนแรงต่อปัญหาแคชข้อมูลในเบราว์เซอร์ เบราว์เซอร์อาจไม่ใช้เวอร์ชันใหม่เนื่องจากชื่อบันเดิลเดียวกัน . เราต้องการวิธี webpack + js + CSS เพื่อจัดการสถานการณ์นี้

เปลี่ยน public / index.html ดังนี้

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

ในการกำหนดค่า webpack ที่ใช้งานจริงให้เปลี่ยนตัวเลือก HtmlWebpackPlugin เป็นด้านล่าง

 new HtmlWebpackPlugin({
          inject: false,
...

คุณอาจต้องใช้คำสั่ง 'eject' เพื่อรับไฟล์การกำหนดค่า webpack ล่าสุดอาจมีตัวเลือกในการกำหนดค่า HtmlWebpackPlugin โดยไม่ต้องนำโครงการออก ป้อนคำอธิบายรูปภาพที่นี่


1

ฉันยังใช้คำตอบของ @Ori Drori และจัดการเพื่อให้มันทำงาน เมื่อรหัสตอบสนองของคุณเติบโตขึ้นชุดข้อมูลจะรวบรวมว่าเบราว์เซอร์ไคลเอ็นต์จะต้องดาวน์โหลดในการเข้าถึงครั้งแรก สิ่งนี้จะกำหนดปัญหาประสบการณ์ผู้ใช้หากคุณจัดการไม่ดี

สิ่งที่ฉันเพิ่มใน @Ori คำตอบคือการเพิ่มและดำเนินการฟังก์ชั่น onload ใน index.html คุณลักษณะ onload ของแท็ก body เพื่อให้ตัวโหลดหายไปหลังจากที่โหลดทุกอย่างในการเรียกดูดู snippet ด้านล่าง:

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

1

สิ่งที่เกี่ยวกับการใช้ Pace

ใช้ที่อยู่ลิงก์นี้ที่นี่

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

1. ในเว็บไซต์ของพวกเขาเลือกสไตล์ที่คุณต้องการและวางใน index.css

2. ไปที่ cdnjs คัดลอกลิงก์สำหรับ Pace Js และเพิ่มไปยังแท็กสคริปต์ของคุณใน public / index.html

3. ตรวจจับการโหลดเว็บโดยอัตโนมัติและแสดงความเร็วที่เบราว์เซอร์ด้านบน

นอกจากนี้คุณยังสามารถปรับความสูงและภาพเคลื่อนไหวใน css ได้อีกด้วย


ยอดเยี่ยมและสามารถบูรณาการในเวลาไม่นาน
UzumakiL
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.