(2024/04/06更新) 因應React在18後更新了許多不同的語法,更新後的教學之後將陸續放在 新的blog 中,歡迎讀者到該處閱讀,我依然會回覆這邊的提問
在前面我們說,過去使用原生JS編寫有規模的專案時,因為要模組化,檔案越分越多,最後零散在各處。為了解決這個問題,後來工程師使用打包工具,把所有的JS檔綁成一個bundle.js
,在第一次執行網頁時就載入所有程式碼。
但是這也造成了一個問題。
「當專案規模過大時,bundle.js
會很大,導致第一次載入網頁的時間太久。」
這個時候我們就會希望把那些「使用者不會很常進去的頁面」從bundle.js
拿出來。但是要怎麼做呢? 難道還要去webpack.config.js
慢慢設定嗎?
在先前,我們要引入component檔案時,是使用:
import InputForm from '../component/InputForm';
而React提供了一個特殊的引入元件方法lazy()
。Babel會把用lazy()
引入的元件在打包時拆成一個獨立的js檔案,並且只有在第一次要渲染該元件的時候,才會引入該js檔。它的用法是
const 元件 = React.lazy(() => import('檔案相對路徑'));
但是元件載入要一段時間,我們要怎麼處理lazy元件還沒被載入的狀況呢?
Suspense是React提供的特殊元件,語法如下:
<Suspense fallback={讀取元件}>目標載入元件</Suspense>;
當「目標載入元件」還沒載入完成時,React會顯示fallback
這個props綁定的「讀取元件」,一直到「目標載入元件」載入完成後再切換過來。
嗯?這樣我們是不是可以把它拿來處理ajax的狀況呢?
的確,React希望在未來的某一天全面讓大家捨棄在useEffect
呼叫http request,並且全面改成使用Suspense
。但目前相關的API還在實驗開發階段,詳請可以參考並關注官方文件。
我們來試著在src/page/FormPage.js使用lazy引入<InputForm />
,並觀察程式碼的狀態:
import React, {lazy, Suspense} from 'react';
const InputForm = lazy(() => import('../component/InputForm'));
import React, {lazy, Suspense} from 'react';
const InputForm = lazy(() => import('../component/InputForm'));
const FormPage = () =>{
return <Suspense fallback={<div>Loading...</div>}>
<InputForm />
</Suspense>;
}
export default FormPage;
npm run build
此時你會發現,build資料夾出現了一個新的檔案
我們去搜尋本來的bundle.js
,會發現裡面沒有InputForm裡面的「提交」按鈕了
而搜尋新的1.bundle.js
,會發現InputForm裡面的「提交」按鈕在它裡面。
最後我們查看執行結果,會發現在第一次切換到FormPage的時候,React去get了這一隻新的1.bundle.js
。
這樣我們就實現了動態延遲載入元件。
需要注意的是,lazy和Suspense目前還不支援Server-side-render,如果你想在相關頁面做SSR,就必須要使用Loadable Components。