來學 React 吧之三_React 中的性能優化


Posted by Christy on 2021-11-07

本文為學習 React 的讀書筆記,從 Lidemy 課程影片從 [FE302] 中的「React 中的性能優化」開始

這篇筆記主要在透過理解 React 底層的運作機制,知道「產生一個新的 state,但重複的東西都要 re-render 是一種資源的浪費」,並且透過三個 React 的 hook(memouseCallbackuseMemo) 來避免 re-render。

React 的要點就是當狀態改變,畫面也改變。即使只新增一列 todo,整個 todo list 也要重新 render,這個特色會對於資源產生浪費。

下面的內容在介紹 React 的運作機制,怎麼透過 virtual DOM 的比對,只更改有變動的地方來節省資源,而這個行為叫做 Reconciliation。

一、React 的渲染機制(Reconciliation)與 Virtual DOM

1. 介紹 React 的運作:透過比對 Virtual DOM 來節省資源,達成 Reconciliation

從前面的影片當中,學到了「每改變畫面一次,就要產生一個新的 state」,React 內部的運作機制是,每改變一個 state,都會產生一個 virtual dom,virtual dom 其實就是一個 JavaScript 的物件。

但是仔細想想,假設總共有一百個 todo,只更改一個,其餘九十九個都要重新產生一次,有點浪費資源,因此這個影片在說的是「要如何在 React 裡面更有效率的做事」。

a.「比對每個 state 所產生的 virtual DOM 的差異」就是所謂的 Reconciliation,指「找出變動的地方再 render」

b. virtual DOM 是一個物件,它可以被轉換成其他不同的形式:例如 virtual dom to real DOM, virtual DOM → 手機形式的語法等等

以上兩點面試絕對會考。

建議閱讀文章:

Virtual DOM | 為了瞭解原理,那就來實作一個簡易 Virtual DOM 吧!

從頭打造一個簡單的 Virtual DOM

Virtual DOM 概述

淺談 React 中的 state 與 useEffect

2. re-render 的幾個層面:

a. 當 state 改變,再呼叫一次 App fn 是一種 re-render

b. 當「與 UI 無關的資料」改變了,例如增加每一列 todo list 的 id 號碼,只會在 virtual dom 那一層比對差異,最後的結果不會放到真的 dom 上面,這也是一種 re-render,但是並沒有改變畫面。要怎麼解決這個無效率的做法呢,讓我們繼續看下去。

二、如何避免 re-render?

這個影片主要介紹如何改善 React 效能三個有關的 hook,分別是 memouseCallbackuseMemo

影片中舉的例子是有一個 todo list,有 input、Add todo 按鈕、顯示 todo list 的區塊;「透過 Add todo 按鈕來觀察什麼時候會 re-render」,嘗試用上述的三種方式來提高效率。

而在這個實驗中,發現當每次抓到 input 裡面的值,按下 Add todo 之後,或者是在按下 Add todo 之後到把內容新增到 todo list 上面時,這些動作都必須要「產生一個新的 state」,因此可知 Add todo 這個按鈕在每次新增 todo 時,都必須被 re-render 一次,這是無法避免的事實。

1. 利用 memo 把一個 component 包起來,來偵測變化,如果有變動才 re-render,memo 是給 component 用的

import { memo } from "react";
const MemoButton = memo(Button)

2. 使用 useCallback 如果 dependencies array 中的值沒有被修改,那 React 就會幫我們記住 object 裡面的值,防止 Object 被重新分配記憶體位址。

useCallback

import { useCallback } from "react";
const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

3. useMemo

useMemo 是給資料用的,memo 是給 component 用的

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

4. 遇到的困難:

剛開始聽的時候真的很混亂,一樣把握幾個原則:

a. 這是什麼

b. 為什麼要用

c. 不用會怎樣

d. 要怎麼用

可能是因為很混亂的關係,因此看了一些資料都沒有看懂。

參考了這篇文章 React 性能優化那件大事,使用 memo、useCallback、useMemo 又重複的把影片看了好多好多遍,才稍微有一點頭緒。

這裡給未來的自己看:「當學習一個新的東西困惑時,關注上述提到的 a, b, c, d 四個要點外,e: 尋找實際案例,f: 直接看官方的說明書也是不錯的辦法」

React 的官方說明書是我的好朋友。

三、React 特別的事件機制

在 React 的事件中,都是使用「事件代理機制」,把監聽器綁在 root 那一層

也就是說,點擊完成按鈕,事件機制綁在 root 裡面,利用事件代理的方式處理

// index.js 裡面
ReactDOM.render(<App />, document.getElementById("root"));









Related Posts

DOM-網路事件處理

DOM-網路事件處理

CSS-[box-shadow]-陰影效果

CSS-[box-shadow]-陰影效果

Conda 常用指令整理

Conda 常用指令整理


Comments