React使用React.lazy和Suspense實(shí)現(xiàn)組件懶加載
在 React 項(xiàng)目里,有時(shí)候組件功能多、體積大,要是一次性把所有組件都加載進(jìn)來(lái),網(wǎng)頁(yè)加載速度就會(huì)變慢。而 React 提供了 React.lazy 和 Suspense 這兩個(gè)好東西,能讓我們實(shí)現(xiàn)組件的懶加載,也就是需要用到某個(gè)組件的時(shí)候再去加載它,這樣可以加快網(wǎng)頁(yè)的初始加載速度。接下來(lái),我就詳細(xì)說(shuō)說(shuō)怎么用這倆來(lái)實(shí)現(xiàn)組件懶加載。
1. 創(chuàng)建項(xiàng)目
首先,你得有個(gè) React 項(xiàng)目。要是還沒(méi)有,就可以用下面這個(gè)命令快速創(chuàng)建一個(gè):
npx create-react-app lazy-loading-example cd lazy-loading-example
2. 創(chuàng)建要懶加載的組件
在 src 目錄下創(chuàng)建一個(gè)新的組件文件,比如叫 LazyComponent.js,這個(gè)組件就是我們要懶加載的對(duì)象。下面是這個(gè)組件的代碼:
// 導(dǎo)入 React 庫(kù)
import React from 'react';
// 定義一個(gè)函數(shù)組件 LazyComponent
const LazyComponent = () => {
// 返回一個(gè)包含文本的 div 元素
return <div>這是一個(gè)懶加載的組件</div>;
};
// 導(dǎo)出這個(gè)組件,以便其他文件可以使用它
export default LazyComponent;
3. 使用 React.lazy 和 Suspense 實(shí)現(xiàn)懶加載
在 src 目錄下的 App.js 文件里,我們要使用 React.lazy 和 Suspense 來(lái)實(shí)現(xiàn)組件的懶加載。下面是具體的代碼:
// 導(dǎo)入 React 庫(kù),同時(shí)引入 React.lazy 和 Suspense
import React, { lazy, Suspense } from 'react';
// 使用 React.lazy 動(dòng)態(tài)導(dǎo)入 LazyComponent 組件
// React.lazy 接收一個(gè)函數(shù),這個(gè)函數(shù)返回一個(gè)動(dòng)態(tài)導(dǎo)入組件的 Promise
const LazyComponent = lazy(() => import('./LazyComponent'));
// 定義 App 函數(shù)組件
const App = () => {
return (
<div>
<h1>組件懶加載示例</h1>
{/* 使用 Suspense 包裹懶加載的組件 */}
{/* fallback 屬性指定在組件加載過(guò)程中顯示的內(nèi)容 */}
<Suspense fallback={<div>正在加載組件...</div>}>
{/* 渲染懶加載的組件 */}
<LazyComponent />
</Suspense>
</div>
);
};
// 導(dǎo)出 App 組件,作為項(xiàng)目的根組件
export default App;
代碼解釋
React.lazy:它就像是一個(gè)小助手,專門負(fù)責(zé)在需要的時(shí)候去加載組件。你給它一個(gè)函數(shù),這個(gè)函數(shù)返回一個(gè)動(dòng)態(tài)導(dǎo)入組件的 Promise,它就會(huì)在合適的時(shí)候去加載這個(gè)組件。
Suspense:它就像一個(gè)緩沖器,在組件加載的過(guò)程中,它會(huì)顯示你設(shè)置的 fallback 內(nèi)容,比如“正在加載組件…”,等組件加載好了,再把組件顯示出來(lái)。
4. 運(yùn)行項(xiàng)目
最后,用下面的命令啟動(dòng)項(xiàng)目:
npm start
當(dāng)你打開(kāi)瀏覽器訪問(wèn)這個(gè)項(xiàng)目的時(shí)候,一開(kāi)始會(huì)看到“正在加載組件…”,等組件加載完成,就會(huì)看到“這是一個(gè)懶加載的組件”。
通過(guò)上面這些步驟,你就學(xué)會(huì)了如何在 React 項(xiàng)目中使用 React.lazy 和 Suspense 實(shí)現(xiàn)組件的懶加載啦。這樣做可以讓你的網(wǎng)頁(yè)加載速度更快,用戶體驗(yàn)也會(huì)更好。
5.組件懶加載其他實(shí)現(xiàn)方法
除了React.lazy和Suspense,還有哪些實(shí)現(xiàn)組件懶加載的方法?
除了 React.lazy 和 Suspense,以下是幾種在 React 里實(shí)現(xiàn)組件懶加載的方法:
1. 手動(dòng)控制導(dǎo)入
可以通過(guò)手動(dòng)管理組件的導(dǎo)入和渲染來(lái)實(shí)現(xiàn)懶加載。在組件需要渲染的時(shí)候,動(dòng)態(tài)地導(dǎo)入相應(yīng)的組件。
import React, { useState } from 'react';
const App = () => {
// 用于存儲(chǔ)懶加載組件的狀態(tài)
const [LazyComponent, setLazyComponent] = useState(null);
// 加載組件的函數(shù)
const loadComponent = async () => {
try {
// 動(dòng)態(tài)導(dǎo)入組件
const { default: component } = await import('./LazyComponent');
// 更新?tīng)顟B(tài)以存儲(chǔ)導(dǎo)入的組件
setLazyComponent(component);
} catch (error) {
console.error('加載組件時(shí)出錯(cuò):', error);
}
};
return (
<div>
<button onClick={loadComponent}>加載組件</button>
{LazyComponent && <LazyComponent />}
</div>
);
};
export default App;
在上述代碼中,loadComponent 函數(shù)在按鈕點(diǎn)擊時(shí)被調(diào)用,它會(huì)動(dòng)態(tài)導(dǎo)入 LazyComponent,并將其存儲(chǔ)在狀態(tài)中。之后,當(dāng) LazyComponent 存在于狀態(tài)中時(shí),就會(huì)渲染該組件。
2. 使用第三方庫(kù) react-loadable(舊版)
react-loadable 是一個(gè)第三方庫(kù),它簡(jiǎn)化了 React 中組件的懶加載過(guò)程。不過(guò)需要注意的是,這個(gè)庫(kù)已經(jīng)不再維護(hù),在 React 16.6 及以后版本中,官方推薦使用 React.lazy 和 Suspense。
首先,安裝 react-loadable:
npm install react-loadable
然后,使用它來(lái)實(shí)現(xiàn)懶加載:
import React from 'react';
import Loadable from 'react-loadable';
// 定義加載時(shí)顯示的組件
const LoadingComponent = () => <div>正在加載...</div>;
// 使用 react-loadable 創(chuàng)建懶加載組件
const LazyComponent = Loadable({
loader: () => import('./LazyComponent'),
loading: LoadingComponent,
});
const App = () => {
return (
<div>
<h1>組件懶加載示例</h1>
<LazyComponent />
</div>
);
};
export default App;
在這段代碼中,Loadable 函數(shù)接收一個(gè)對(duì)象,其中 loader 屬性是一個(gè)返回動(dòng)態(tài)導(dǎo)入組件的函數(shù),loading 屬性指定了在組件加載過(guò)程中顯示的組件。
3. 基于路由的懶加載
在使用 React Router 進(jìn)行路由管理時(shí),可以實(shí)現(xiàn)基于路由的懶加載。這樣當(dāng)用戶訪問(wèn)特定路由時(shí),才加載對(duì)應(yīng)的組件。
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
// 懶加載 Home 組件
const Home = lazy(() => import('./Home'));
// 懶加載 About 組件
const About = lazy(() => import('./About'));
const App = () => {
return (
<Router>
<Suspense fallback={<div>正在加載...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</Router>
);
};
export default App;
這里,當(dāng)用戶訪問(wèn)不同的路由時(shí),對(duì)應(yīng)的組件才會(huì)被動(dòng)態(tài)加載。Suspense 組件用于在加載過(guò)程中顯示提示信息。
對(duì)比React.lazy和Suspense以及手動(dòng)控制導(dǎo)入這三種方式的優(yōu)缺點(diǎn)
以下是對(duì) React.lazy 和 Suspense 以及手動(dòng)控制導(dǎo)入這三種組件懶加載方式優(yōu)缺點(diǎn)的對(duì)比:
React.lazy 和 Suspense
優(yōu)點(diǎn)
1.語(yǔ)法簡(jiǎn)潔:React.lazy 和 Suspense 是 React 官方提供的懶加載解決方案,使用起來(lái)語(yǔ)法簡(jiǎn)潔直觀。例如,使用 React.lazy 只需一行代碼就能定義一個(gè)懶加載組件,Suspense 也能很方便地設(shè)置加載時(shí)的占位內(nèi)容。
const LazyComponent = lazy(() => import('./LazyComponent'));
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
2.與 React 生態(tài)集成良好:作為 React 官方特性,它能與 React 的其他特性(如 React Router)無(wú)縫集成,方便在路由層面實(shí)現(xiàn)懶加載,使代碼結(jié)構(gòu)更清晰。
const Home = lazy(() => import('./Home'));
<Route path="/" element={
<Suspense fallback={<div>Loading...</div>}>
<Home />
</Suspense>
} />
3.自動(dòng)處理錯(cuò)誤和加載狀態(tài):Suspense 可以自動(dòng)處理組件加載過(guò)程中的狀態(tài),當(dāng)組件加載失敗時(shí),也可以結(jié)合 ErrorBoundary 來(lái)捕獲和處理錯(cuò)誤,增強(qiáng)了應(yīng)用的健壯性。
缺點(diǎn)
兼容性依賴 React 版本:React.lazy 和 Suspense 是 React 16.6 及以上版本才支持的特性,如果項(xiàng)目使用的是舊版本的 React,則無(wú)法使用該功能。
靈活性相對(duì)較低:在某些復(fù)雜場(chǎng)景下,React.lazy 和 Suspense 的默認(rèn)行為可能無(wú)法滿足需求,例如需要更精細(xì)地控制組件加載時(shí)機(jī)。
手動(dòng)控制導(dǎo)入
優(yōu)點(diǎn)
高度靈活:手動(dòng)控制導(dǎo)入允許你完全自主地控制組件的加載時(shí)機(jī)和方式。你可以根據(jù)不同的條件(如用戶操作、數(shù)據(jù)加載狀態(tài)等)來(lái)決定何時(shí)加載組件,適用于各種復(fù)雜的業(yè)務(wù)場(chǎng)景。
const [LazyComponent, setLazyComponent] = useState(null);
const loadComponent = async () => {
const { default: component } = await import('./LazyComponent');
setLazyComponent(component);
};
<button onClick={loadComponent}>Load Component</button>
兼容性好:這種方式不依賴于特定的 React 版本,只要支持動(dòng)態(tài)導(dǎo)入語(yǔ)法,就可以在任何 React 項(xiàng)目中使用。
缺點(diǎn)
代碼復(fù)雜度高:手動(dòng)控制導(dǎo)入需要編寫更多的代碼來(lái)管理組件的加載狀態(tài)和錯(cuò)誤處理,代碼結(jié)構(gòu)會(huì)變得復(fù)雜,維護(hù)成本較高。
const loadComponent = async () => {
try {
const { default: component } = await import('./LazyComponent');
setLazyComponent(component);
} catch (error) {
console.error('Failed to load component:', error);
// 還需要額外處理錯(cuò)誤狀態(tài)
}
};
缺乏統(tǒng)一的加載狀態(tài)管理:不像 Suspense 可以統(tǒng)一管理加載狀態(tài)和占位內(nèi)容,手動(dòng)控制導(dǎo)入需要自己實(shí)現(xiàn)加載狀態(tài)的管理,容易出現(xiàn)不一致的情況。
除了懶加載,還有哪些優(yōu)化React項(xiàng)目性能的方法?
6.React 項(xiàng)目性能方法
除了懶加載,以下是一些優(yōu)化 React 項(xiàng)目性能的常用方法:
1. 虛擬列表
當(dāng)需要渲染大量數(shù)據(jù)列表時(shí),一次性渲染所有數(shù)據(jù)會(huì)導(dǎo)致性能問(wèn)題。虛擬列表只渲染當(dāng)前可見(jiàn)區(qū)域的數(shù)據(jù),當(dāng)用戶滾動(dòng)列表時(shí),動(dòng)態(tài)地加載和渲染新的數(shù)據(jù)。
import React from 'react';
import { FixedSizeList } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>
這是第 {index} 行數(shù)據(jù)
</div>
);
const App = () => {
return (
<FixedSizeList
height={400}
width={300}
itemSize={30}
itemCount={1000}
>
{Row}
</FixedSizeList>
);
};
export default App;
這里使用了 react-window 庫(kù)的 FixedSizeList 組件,它會(huì)根據(jù)列表的高度、寬度、每個(gè)項(xiàng)的大小和項(xiàng)的總數(shù),只渲染當(dāng)前可見(jiàn)區(qū)域的項(xiàng)。
2. 使用 shouldComponentUpdate、PureComponent 或 React.memo
shouldComponentUpdate
在類組件中,可以通過(guò) shouldComponentUpdate 生命周期方法來(lái)控制組件是否需要重新渲染。通過(guò)比較前后的 props 和 state,決定是否阻止組件的重新渲染。
class MyComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
// 比較前后的 props 和 state,返回 false 則阻止重新渲染
return this.props.someProp!== nextProps.someProp || this.state.someState!== nextState.someState;
}
render() {
return <div>{this.props.someProp}</div>;
}
}
PureComponent
PureComponent 是 React 提供的一個(gè)基類,它會(huì)自動(dòng)對(duì) props 和 state 進(jìn)行淺比較,如果沒(méi)有變化則阻止組件重新渲染。
import React, { PureComponent } from 'react';class MyPureComponent extends PureComponent {
render() {
return <div>{this.props.someProp}</div>;
}
}
React.memo
對(duì)于函數(shù)組件,可以使用 React.memo 來(lái)實(shí)現(xiàn)類似的功能。React.memo 是一個(gè)高階組件,它會(huì)對(duì)組件的 props 進(jìn)行淺比較,只有當(dāng) props 發(fā)生變化時(shí)才會(huì)重新渲染組件。
import React from 'react';
const MyFunctionComponent = React.memo((props) => {
return <div>{props.someProp}</div>;
});
3. 優(yōu)化事件處理函數(shù)
在 React 中,每次渲染時(shí)創(chuàng)建新的事件處理函數(shù)會(huì)導(dǎo)致不必要的性能開(kāi)銷??梢栽陬惤M件的構(gòu)造函數(shù)中綁定事件處理函數(shù),或者使用箭頭函數(shù)定義事件處理函數(shù)。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// 處理點(diǎn)擊事件
}
render() {
return <button onClick={this.handleClick}>點(diǎn)擊我</button>;
}
}
4. 優(yōu)化 CSS 樣式
避免使用內(nèi)聯(lián)樣式,因?yàn)閮?nèi)聯(lián)樣式會(huì)在每次渲染時(shí)重新計(jì)算和應(yīng)用??梢允褂?CSS 類名來(lái)管理樣式,這樣瀏覽器可以更好地緩存和優(yōu)化樣式。
import './styles.css';
const MyComponent = () => {
return <div className="my-style">這是一個(gè)組件</div>;
};
5. 代碼分割和打包優(yōu)化
合理地進(jìn)行代碼分割,將不常用的代碼分離到單獨(dú)的包中,減少初始加載的代碼量??梢允褂?Webpack 等打包工具的配置來(lái)實(shí)現(xiàn)代碼分割,例如使用動(dòng)態(tài)導(dǎo)入語(yǔ)法。
const loadComponent = async () => {
const { default: MyComponent } = await import('./MyComponent');
// 使用組件
};
6. 使用 useCallback 和 useMemo
useCallback
useCallback 用于緩存函數(shù),避免在每次渲染時(shí)創(chuàng)建新的函數(shù)實(shí)例。當(dāng)函數(shù)作為 props 傳遞給子組件時(shí),使用 useCallback 可以避免子組件不必要的重新渲染。
import React, { useCallback } from 'react';
const MyComponent = () => {
const handleClick = useCallback(() => {
// 處理點(diǎn)擊事件
}, []);
return <button onClick={handleClick}>點(diǎn)擊我</button>;
};
useMemo
useMemo 用于緩存計(jì)算結(jié)果,避免在每次渲染時(shí)進(jìn)行重復(fù)的計(jì)算。當(dāng)某個(gè)計(jì)算結(jié)果依賴于某些值,并且這些值沒(méi)有變化時(shí),使用 useMemo 可以直接返回之前的計(jì)算結(jié)果。
import React, { useMemo } from 'react';
const MyComponent = ({ a, b }) => {
const sum = useMemo(() => a + b, [a, b]);
return <div>總和是: {sum}</div>;
};到此這篇關(guān)于React使用React.lazy和Suspense實(shí)現(xiàn)組件懶加載的文章就介紹到這了,更多相關(guān)React組件懶加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React videojs 實(shí)現(xiàn)自定義組件(視頻畫質(zhì)/清晰度切換) 的操作代碼
最近使用videojs作為視頻處理第三方庫(kù),用來(lái)對(duì)接m3u8視頻類型,這里總結(jié)一下自定義組件遇到的問(wèn)題及實(shí)現(xiàn),感興趣的朋友跟隨小編一起看看吧2023-08-08
React?組件權(quán)限控制的實(shí)現(xiàn)
本文主要介紹了React?組件權(quán)限控制的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
react component changing uncontrolled in
這篇文章主要為大家介紹了react component changing uncontrolled input報(bào)錯(cuò)解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
關(guān)于hooks中useEffect()的使用總結(jié)
這篇文章主要介紹了關(guān)于hooks中useEffect()的使用總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
React之如何在Suspense中優(yōu)雅地請(qǐng)求數(shù)據(jù)
Suspense 是 React 中的一個(gè)組件,直譯過(guò)來(lái)有懸掛的意思,能夠?qū)⑵浒漠惒浇M件掛起,直到組件加載完成后再渲染,本文詳細(xì)介紹了如何在Suspense中請(qǐng)求數(shù)據(jù),感興趣的小伙伴可以參考閱讀本文2023-04-04
React實(shí)現(xiàn)預(yù)覽展示docx和Excel文件
這篇文章主要為大家詳細(xì)介紹了如何使用React實(shí)現(xiàn)預(yù)覽展示docx和Excel文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02

