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