動態import
在說lazy
和suspense
之前,還是先說說動態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;
}
}