前言 這一篇要來介紹 React Router 中很重要一個優化的部分,也就是 Lazy Loading,Lazy Loading 在實在開發上其實是非常重要的,它可以將我們的程式碼分割成不同的 chunk,然後在你需要或請求的時候才去載入相對應檔案,所以這一篇就會來介紹 Lazy Loading 的部分。
Lazy Loading 這邊我們將會使用這一份範例程式碼 當作示範。
當你下載了前面的範例程式碼後,接著你可以在終端機輸入 npm run build 來看一下打包狀況,你會發現打包出來的檔案會是這樣的:
1 2 3 4 5 6 7 8 > [email protected] build > vite build vite v3.1.4 building for production... ✓ 39 modules transformed. dist/index.html 0.44 KiB dist/assets/index.f9c6795a.css 4.70 KiB / gzip: 1.53 KiB dist/assets/index.50715e86.js 157.74 KiB / gzip: 51.15 KiB
我們可以看到上方中有一個 dist/assets/index.50715e86.js,這個檔案就是我們的整個專案打包編譯後的程式碼,而這個檔案大小為 157.74 KiB,雖然看起來好像沒有很大,但是如果我們的專案越來越龐大時,這個檔案也會跟著越來越大,那麼就會導致一些問題發生,其中最明顯的就是使用者在瀏覽網頁時,會因為網頁的載入時間太長而導致使用者離開,所以這時候就需要 Lazy Loading 來幫助我們。
當你使用了 Lazy Loading 之後,你會發現打包出來的檔案會類似變成這樣子
1 2 3 4 5 6 7 8 9 10 11 12 > [email protected] build > vite build vite v3.1.4 building for production... ✓ 40 modules transformed. dist/index.html 0.44 KiB dist/assets/Products.6a1dfb49.js 0.14 KiB / gzip: 0.14 KiB dist/assets/App.2df53b30.js 0.11 KiB / gzip: 0.12 KiB dist/assets/ToDoList.1f52c4c4.js 0.13 KiB / gzip: 0.13 KiB dist/assets/Admin.868445da.js 0.13 KiB / gzip: 0.13 KiB dist/assets/index.f9c6795a.css 4.70 KiB / gzip: 1.53 KiB dist/assets/index.df8ef9bc.js 158.30 KiB / gzip: 51.47 KiB
我們可以看到整體檔案縮小了相當多,透過 Lazy Loading 我們可以將我們的程式碼分割成不同的 chunk,然後在你需要或請求的時候才去載入相對應檔案,所以這邊我們就來看一下怎麼使用 Lazy Loading 吧。
首先打開放在 routes 資料夾中的 index.js,接著我們可以看到這樣的程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import { useRoutes } from 'react-router-dom' ;import App from '../App' ;import ToDoList from '../ToDoList' ;import Products from '../Products' ;import Admin from '../Admin' ;const routes = [ { path : '/' , element : <App /> , }, { path : '/todolist' , element : <ToDoList /> , }, { path : '/products' , element : <Products /> , }, { path : '/admin' , element : <Admin /> , } ];export default () => useRoutes (routes);
接著我們要在最上方引入 lazy 這個函式
1 import { lazy } from 'react' ;
那麼 lazy 是什麼呢?簡單來說就是一個函式,這個函式可以讓我們在需要的時候才去載入相對應的程式碼,而不是一開始就載入所有程式碼,所以我們可以將 App、ToDoList、Products、Admin 這四個元件都改成使用 lazy 來載入
1 2 3 4 5 6 import { lazy } from 'react' ;const App = lazy (() => import ('../App' ));const ToDoList = lazy (() => import ('../ToDoList' ));const Products = lazy (() => import ('../Products' ));const Admin = lazy (() => import ('../Admin' ));
接下來我們要在 App.js 中引入 Suspense 這個元件,這個元件可以讓我們在載入元件時顯示一些 Loading 的畫面,基本使用方式很簡單
1 <Suspense fallback={ Loading 元件 }>即將載入的元件<Suspense >
那為什麼要使用 Suspense 呢?主要原因是因為元件是使用 lazy 來載入的,所以在載入元件時會有一些延遲,所以我們可以使用 Suspense 來顯示一些 Loading 的畫面,讓使用者知道正在載入中,而不是一直等待載入完成,所以我們可以在 App.js 中加入 Suspense 來顯示 Loading 畫面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { StrictMode , Suspense } from 'react' import { HashRouter , NavLink } from "react-router-dom" ;import ReactDOM from 'react-dom/client' import Router from './routes' import './index.css' ;ReactDOM .createRoot (document .getElementById ('root' )).render ( <StrictMode > <HashRouter > <nav className ="px-5 flex items-center h-[60px] bg-indigo-500 text-white" > {/* ...略過 */} </nav > <Suspense fallback ={ <div > Loading...</div > }> <Router /> </Suspense > </HashRouter > </StrictMode > )
Suspense 的 fallback 這個屬性是可以接收一個元件的,所以上方我們放入了一個 div,裡面放入 Loading... 的文字,這樣當我們載入元件時就會顯示 Loading... 的文字,而不是一直等待載入完成。
但是這邊要注意,若你沒有使用 Suspense 的話,是會出現以下的錯誤訊息
1 Uncaught Error: A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition.
因此我們必須要使用 Suspense 來顯示 Loading 畫面,這樣才不會出現錯誤訊息。
那麼剛剛有提到 fallback 也可以寫入一個元件來使用,所以這邊就簡單示範一下,首先先建立一個 components/Loading.js 來放入一個 Loading 的元件
1 2 3 4 5 6 7 8 9 10 const Loading = ( ) => { return ( <div className ="flex justify-center items-center h-screen bg-indigo-500" > <img src ="https://i.imgur.com/0HSGxif.gif" alt ="" className ="w-[150px] h-[150px] " /> </div > ) }export default Loading ;
接下來在 main.jsx 引入並將 Suspense 的 fallback 替換成 Loading 元件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { StrictMode , Suspense } from 'react' import { HashRouter , NavLink } from "react-router-dom" ;import ReactDOM from 'react-dom/client' import Router from './routes' import Loading from './components/Loading' ;import './index.css' ;ReactDOM .createRoot (document .getElementById ('root' )).render ( <StrictMode > <HashRouter > <nav className ="px-5 flex items-center h-[60px] bg-indigo-500 text-white" > {/* ...略過 */} </nav > <Suspense fallback ={ <Loading /> }> <Router /> </Suspense > </HashRouter > </StrictMode > )
接下來只要是初次載入的元件畫面都會出現 Loading 的畫面,而當你第二次載入時,就不會再出現 Loading 的畫面了。
那麼這一篇就先到這邊結束囉~
範例程式碼一樣上傳到這邊 。
後記 本文將會同步更新到我的部落格
整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ
Advertisement