React 的渲染機制(Reconciliation)
回顧 Todolist
新增 todo 的時候,去更改資料,然後由資料去反應畫面,來保持資料與畫面永遠一致。
假如我們現在有 100 個 todolist,當新增一個,就要把畫面重新清空,再 render,效能上就會有差別。
如何快速找到要改變的地方
state 改變,渲染了出舊 & 新的虛擬 DOM (JS 的物件),透過 diff 演算法可以進行新舊比對,比對的過程稱為:Reconciliation
Virtual DOM 的特點
diff 演算法比較 Virtual DOM 修改前與修改後的樹狀結構,然後批次更新真實 DOM 中的節點。
透過新舊虛擬 DOM 比對的過程,可以比較快找到兩者相異處。我們為 todoItem 加上 key 也是加快比對的速度。
因為虛擬 DOM 的存在,我們可以使用同樣的原始碼(JS 物件)render 出網站、手機 APP、投影片程式。
補充:Virtual DOM 保證的並不是在所有狀況下都比操作原本的 DOM 來得快速,而是在普遍狀況下,不需經手動優化,仍能給予不錯的效能。
如何避免 re-render
重點整理:
memo()
<-- 包住 componentuseCallback()
useMemo()
- 舉個例子:todolist Button
父層 re-render,子層也會一起 re-render
// 另外拆成一個 component
function Button( {onClick, children }) {
console.log("render button");
return <button onClick={onClick}>{children}</button>
}
function App() {
// 打字的時候,value 改變就會 re-render,同步子層 Button 也會一起,但他其實不需要 re-render
return (
<div className="App">
<input
type="text"
placeholder="todo"
value={value}
onChange={handleChange}
/>
<Button onClick={handleButtonClick}>Add todo</Button>
</div>
)
}
- 如何使用
memo()
檢查Button()
傳入的 props 有沒有改變,如果沒有改變,就不會 re-render。
@ App.js
import { memo } from "react";
function Button( {onClick, children }) {
console.log("render button");
return <button onClick={onClick}>{children}</button>
}
const MemoButton = memo(Button)
function App() {
// 打字的時候,value 改變就會 re-render,同步子層 Button 也會一起,但他其實不需要 re-render
return (
<div className="App">
<input
type="text"
placeholder="todo"
value={value}
onChange={handleChange}
/>
<Button onClick={handleButtonClick}>Add todo</Button>
</div>
)
}
useCallback
:阻止 button 裡面,onClick 事件
使用了memo()
,但 onClick 還是會影響 re-render,
@ useTodos.js
// 第一次 render 時會改變。
const handleButtonClick = useCallback(() => {
console.log(value)
setTodos([
{
id: id.current,
content: value
}.
...todos,
])
setValue("");
id.current++;
}, [setValue, setTodos, value, todos])
useMemo()
只有 value 改變的時候,才會去重新渲染 s 的值。
const s = useMemo(() => {
const.log("calculate s")
return value ? redStyle : blueStyle;
}, [value]);
React 特別的事件機制
React 是用事件代理的機制來進行。監聽的事件是綁在 #root 上面。
- 效能比較好
- 動態新增、刪除,確保
eventlistener
能捕捉到正確的資料