React之lazy與suspense

動態import

在說lazysuspense之前,還是先說說動態import這種語法。

import語句我們使用的很多,通常是import ... from '...'這樣的寫法,這樣的寫法也被稱作是靜態加載。

而所謂的動態import或者說動態加載,就是指在運行時加載。寫法如下:

import('./test.js').then(test => {
    ...
});

可以發現,動態import實現了Promise規範,回調函數的test參數就是加載完成後的模塊。

這麼寫有什麼好處呢?一個頁面中也許會有許多的邏輯代碼並不需要在頁面加載時加載,也許是在觸發了某個事件如點擊之後才需要加載。那麼通過動態加載就可以實現這一點,好處在於可以加快頁面加載的速度。

lazy

對於一段JS代碼,我們可以在需要的時候通過動態import的方式異步加載,那麼對於一個React模塊,什麼是“需要的時候”?到了這個時候又該怎麼加載呢?

對於React模塊,這個“需要的時候”自然就是要渲染它的時候,而想要在這個時候實現異步加載就需要使用React 16.6中新增的lazy方法了。

lazy是一個方法,它封裝了“動態加載的過程”,如果對這句話不太明白,看下面的代碼就能理解:

import React, { lazy, Component } from 'react';
const Later = lazy(() => import('./Later'));

上面代碼中的Later是一個React組件,但它並不能被渲染,它只是一個“動態加載過程”的封裝。它在要被渲染的時候就會去加載真正的Later組件。

lazy方法接受一個無參數的函數,函數必須執行動態import。

那是不是直接這樣使用就可以了呢?

import React, { lazy, Component } from 'react';
const Later = lazy(() => import('./Later'));

export default class App extends Component {
  render() {
    return (
      <div> 
          <Later />  
      </div>
    );
  }
}

可以發現在瀏覽器中是會報錯的:

在這裏插入圖片描述
出現這個報錯就需要用到suspense了。

suspense

既然是動態加載,那麼也就是說會有一個加載過程,那麼在這個加載過程中就需要一個UI組件,來在等待過程中顯示一些UI。

import React, { Component, lazy, Suspense } from 'react';

const Later = lazy(() => import('./Later'));
export default class App extends Component {
 render() {
   return (
     <div> 
       <Suspense fallback={<div>loading...</div>}>
         <Later />  
       </Suspense>
     </div>
   );
 }
}

這樣就會在Later加載完成之前顯示“loading…”字樣。

suspense組件有一個fallback屬性,它就是用來接收加載過程中顯示的組件的。suspense內部是可以包裹多個組件的。

Error boundaries

Error boundaries,中文意爲錯誤邊界。我們希望部分UI的錯誤不會導致整個程序的崩潰,以及希望在錯誤發生時能夠顯示對應的UI。

錯誤邊界是一種 React 組件,這種組件可以捕獲並打印發生在其子組件樹任何位置的 JavaScript 錯誤,並且,它會渲染出備用 UI,而不是渲染那些崩潰了的子組件樹。錯誤邊界在渲染期間、生命週期方法和整個組件樹的構造函數中捕獲錯誤。

如果一個 class 組件中定義了 static getDerivedStateFromError()componentDidCatch() 這兩個生命週期方法中的任意一個(或兩個)時,那麼它就變成一個錯誤邊界。當拋出錯誤後,請使用 static getDerivedStateFromError() 渲染備用 UI ,使用 componentDidCatch() 打印錯誤信息。

getDerivedStateFromError

此生命週期會在後代組件拋出錯誤後被調用。 它將拋出的錯誤作爲參數,並返回一個值以更新 state。

注:getDerivedStateFromError() 會在渲染階段調用,因此不允許出現副作用。 如遇此類情況,請改用 componentDidCatch()。

componentDidCatch

此生命週期在後代組件拋出錯誤後被調用。 它接收兩個參數:

  • error —— 拋出的錯誤。
  • info —— 帶有 componentStack key 的對象,其中包含有關組件引發錯誤的棧信息。

注:componentDidCatch() 會在“提交”階段被調用,因此允許執行副作用。 它應該用於記錄錯誤之類的情況。

import React, { Component } from 'react';

export default class MyError extends Component {
    constructor(props){
        super(props);
        this.state = {
            hasError: false
        };
    }

    static getDerivedStateFromError(err){
        return {hasError: true};
    }

    componentDidCatch(err, errinfo){
        console.log(err);
        console.log(errinfo);
    }

    render() {
        const { hasError } = this.state;
        if(hasError){
            return <div>Something wrong!!!</div>
        }
        return this.props.children;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章