代碼分割
import 靜動(dòng)態(tài)導(dǎo)入
- 靜態(tài)導(dǎo)入:static import
import xxx from 'xxx'
導(dǎo)入并加載時(shí),導(dǎo)入的模塊會(huì)被編譯,不是按需編譯 - 動(dòng)態(tài)導(dǎo)入:dynamic import
import('xxx')
根據(jù)條件或按需的模塊導(dǎo)入
動(dòng)態(tài)導(dǎo)入應(yīng)用場(chǎng)景:
- 模塊太大了,使用可能性很低的模塊是存在的,這些模塊不需要馬上加載
- 模塊的導(dǎo)入占用大量的系統(tǒng)內(nèi)存
- 模塊需要異步獲取
- 導(dǎo)入模塊時(shí),需要?jiǎng)討B(tài)構(gòu)建路徑
import('./' + a + b + '.js')// 動(dòng)態(tài)說(shuō)明符(靜態(tài)導(dǎo)入只支持靜態(tài)說(shuō)明符:'./a/b/c.js') - 模塊中的代碼需要程序觸發(fā)了某些條件才運(yùn)行
不要濫用動(dòng)態(tài)導(dǎo)入,靜態(tài)導(dǎo)入是有利于初始化依賴,靜態(tài)的程序分析和
tree sharking靜態(tài)導(dǎo)入會(huì)使其更好的工作
babel 解析 import() 依賴 @babel/plugin-syntax-dynamic-import
// index.module
export default class Test{
constructor(){
console.log('new Test');
}
}
// 動(dòng)態(tài)導(dǎo)入返回一個(gè) promise,res 接收模塊的默認(rèn)導(dǎo)出
import("./index.module").then((res) => {
console.log(res);
new res.default();
});
lazy 內(nèi)置方法 / Suspense React 內(nèi)置組件
lazy 是 React 提供的懶(動(dòng)態(tài))加載組件的方法 React.lazy(函數(shù):動(dòng)態(tài)導(dǎo)入組件),該函數(shù)返回一個(gè) Promise
減少打包體積,對(duì)初次渲染不適用的組件延遲加載
依賴內(nèi)置組件 Suspense,給 lazy 加上 loading 指示器的一個(gè)容器組件
// ./lazy/Loading.jsx
export default class Loading extends React.Component {
render() {
return <div>Loading...</div>;
}
}
// ./lazy/Main.jsx
export default class Main extends React.Component {
render() {
return <div>Main</div>;
}
}
// index.jsx
// lazy 接收一個(gè)動(dòng)態(tài)導(dǎo)入組件的函數(shù)
// 該函數(shù)返回一個(gè) promise
// promise 會(huì) resolve 一個(gè)默認(rèn)導(dǎo)出(export default)的 React 組件
// Suspense 只和 lazy 配合實(shí)現(xiàn)組件等待加載指示器的功能
import Loading from "./lazy/Loading";
const MainComponent = React.lazy(() => import("./lazy/Main"));
class App extends React.Component {
render() {
return (
<React.Suspense fallback={Loading}>
<MainComponent />
</React.Suspense>
);
}
}
ReactDOM.render(<App />, document.querySelector("#app"));
yarn add react-router react-router-dom -D
錯(cuò)誤邊界
React 16 增加的組件
- 防止某個(gè)組件的
UI渲染錯(cuò)誤導(dǎo)致整個(gè)應(yīng)用崩潰 - 子組件發(fā)生
js錯(cuò)誤,有備用的渲染UI - 錯(cuò)誤邊界其實(shí)是一個(gè)組件,只能用
class來(lái)寫(xiě)
getDerivedStateFromError(error)
參數(shù):子組件拋出的錯(cuò)誤
返回新的 state
作用:獲取捕獲的錯(cuò)誤,修改錯(cuò)誤裝填
渲染階段調(diào)用,不允許出現(xiàn)副作用:setTimeout、requestAnimationFrame
錯(cuò)誤邊界組件捕獲錯(cuò)誤的時(shí)機(jī):渲染時(shí)、生命周期函數(shù)中、組件樹(shù)的構(gòu)造函數(shù)中
錯(cuò)誤邊界組件可以嵌套使用,且有冒泡機(jī)制,捕獲的錯(cuò)誤會(huì)一直往上拋,也就是說(shuō),里面的錯(cuò)誤邊界組件報(bào)錯(cuò)了,外層的錯(cuò)誤組件可以捕獲到
無(wú)法捕獲的場(chǎng)景:
- 事件處理函數(shù)內(nèi)部錯(cuò)誤
- 異步代碼
setTimeout、ajax、requestAnimationFrame - 服務(wù)端渲染(因?yàn)橛|發(fā)更新只能在客戶端進(jìn)行,不能在serve端進(jìn)行)
- 錯(cuò)誤邊界組件內(nèi)部錯(cuò)誤
componentDidCatch
原型上的方法,componentDidCatch(error, info)
參數(shù):
-
error:拋出的錯(cuò)誤 - 組件引發(fā)錯(cuò)誤相關(guān)的信息,組件棧
作用:錯(cuò)誤信息獲取,運(yùn)行副作用
邊界錯(cuò)誤組件捕獲異常,并進(jìn)行后續(xù)處理
在該組件拋出錯(cuò)誤后調(diào)用
class ErrorBoundary extends React.Component {
state = {
hasError: false,
};
static getDerivedStateFromError(error) {
console.log(1);
return { hasError: true };
}
componentDidCatch(error, info) {
console.log(2);
console.log(otherParams);
console.log(error, info);
}
render() {
if (this.state.hasError) {
return <h1>hasError</h1>;
}
return this.props.children;
}
}
class MyError extends React.Component {
state = {
hasError: false,
};
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
console.log(error, info);
}
render() {
if (this.state.hasError) {
return <h1>My-Error</h1>;
}
return this.props.children;
}
}
class Test extends React.Component {
render() {
// const data = {
// title: 9999,
// };
return <div>{data.title}</div>;
}
}
class Sub extends React.Component {
render() {
return <div>sub content</div>;
}
}
class App extends React.Component {
render() {
return (
<div>
<MyError>
<ErrorBoundary>
<Test />
</ErrorBoundary>
</MyError>
<Sub />
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector("#app"));