React.memo
是一個高階組件,主要用於優化性能,跟 PureComponent
類似,差別在於 PureComponent
是用於包裝 class component,memo
是用於包裝 function component。它主要的功能是去比較 props的變化,如果父元件傳入子元件的
props 沒有變化,
memo 就不會重新渲染,而是使用上一次的渲染結果。memo
的使用方式也很簡單,只要調用 React.memo
並把元件傳進去就可以,就像下面的範例
const UserProfile = React.memo((props) => {
const { data } = this.props
return <div>
{ data }
</div>
})
memo
也可以自定義比較函式,下面的例子,我們自定義一個 isEqual
函式,它會傳進舊和新的 props
並且比較是否不同,如果不同就返回 false
,元件就會重新渲染。
const UserProfile = (props) => {
const { data } = this.props
return <div>
{ data }
</div>
}
// 比較函式
const isEqual = (prevProps, nextProps) => {
if (prevProps !== nextProps) {
return false
}
}
export default React.memo(UserProfile, isEqual)
大多數的 React 專案都會透過 Webpack 之類的工具打包,將所有檔案合併成一個可以被網頁載入的檔案。但是當專案越來越大,使用許多第三方套件時,打包後的檔案也會很大,導致網頁初次渲染時很慢,這時候就需要 Code-splitting,讓我們只加載當前頁面需要的程式碼。它的原理是將專案打包成多個檔案,避免使用者載入目前不須使用的程式碼,減少初次載入的時間。
動態 import()
是 ES6 新增的語法,是實現 Code Splitting 的基礎,它和我們平常直接使用 import 的方式不同,並不是返回一個元件,而是返回一個 Promise
,因此必須再用其他的方式去取得資料,例如 React 內建處理的 React.lazy
或是像第三方套件 loadable-components 都可以處理。
以下面的程式碼為例,Webpack 在讀取到這種程式碼時候,就會自動啟動 code-splitting,不過需要在 Webpack 中去做一些 Code Splitting 的設定。
// 一般 import
import { add } from './math';
console.log(add(16, 26));
// 動態 import
import("./math").then(math => {
console.log(math.add(16, 26));
});
如果是使用 create-react-app 或 Next.js 的話,本身就內建支援 Code Splitting 了,以下面圖的為例,是我們在之前個人履歷網頁練習的專案,經過打包之後,我們可以看 build 資料夾底下, static 內的 js 資料夾,裡面分成很多支檔案,這就是 Code Splitting 分割後的結果。
React.lazy
讓我們可以 render
一個動態 import
的元件,它的使用方式很簡單,在裡面傳入一個回調函式,返回值就是前面提到的動態 import
,透過這個方式,將其轉為正常的元件,讓我們可以調用。
import UserData from './UserData';
// 利用 React.lazy 轉化動態 import 的 UserData 元件
const UserData = React.lazy(() => import('./UserData'));
// 調用 UserData 元件
const UserProfile = () => {
return <div>
<UserData />
</div>
}
lazy component 必須在 Suspense component 內 render
,否則會報錯,React.Suspense
主要有以下幾個功能
fallback
,像是 loading。React.Suspense
的方式也很簡單,只要直接調用 Suspense component,並將 lazy component 放進去就可以了,只是 Suspense
裡面必須有一個 fallback
屬性,放入加載時的元件或 JSX,如下面範例中的 <div>loading...</div>
。import UserData from './UserData';
// 利用 React.lazy 轉化動態 import 的 UserData 元件
const UserData = React.lazy(() => import('./UserData'));
// 調用 UserData 元件
const UserProfile = () => {
return <div>
<React.Suspense fallback={ <div>loading...</div> }>
<UserData />
</React.Suspense>
</div>
}
React.lazy
和 React.Suspense
目前還不支持服務端渲染,如果是使用服務端渲染,可以使用前面提到的第三方套件 loadable-components 處理。
從這篇可以看出來 React 的高級性能主要都是在優化效能,memo
起到了在渲染時優化的功用,而 React.lazy
和 React.Suspense
讓我們可以在 React 中實行程式碼分離,讓專案在網頁上渲染時能更有效率的載入。