認識 React Hook
Hook 是什麼?
Hook 是函式,是一種重複使用邏輯的方法,能用來在不同的 Component 之間重複使用邏輯,可以讓 function component 使用原本只有 class component 有的 state 和生命週期功能。
Q: 使用 React Hook 有什麼限制嗎?
- 只能在 functional component 中呼叫 Hook,class component 不能使用
- 只能在最上層呼叫,不能在迴圈、條件式或巢狀函式內呼叫,以確保 Hook 被呼叫的順序
useState
//useState是函式,會回傳一個值 state ,以及更新該 state 的方法(setState)
const [state, setState] = useState(initialState);
useState 是用來在 function component 裡面保留 local state。一般情況下,變數會在 function 結束時消失,但 state 變數會被 React 保留起來,因此,在重新渲染時元件仍會保留這個 state。使用 setState 方法將會更新 state,不會直接修改 state 而是給一個 newState 。
一個元件內可以宣告多個 state ,因此,不用將各種無關的 state 放在同一個物件內。
注意: setState 不會即時更新,是非同步的
關於 initialState
initialState 參數只會在第一次渲染時使用,後續渲染時不會用到,但每次渲染時還是會跑一次 initialState。 如果初始 state 需要通過複雜的計算來獲得,可以傳入 function,並回傳初始值
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
要注意的是因為每次渲染都還是會跑 initialState,基於效能可量,要避免以下的寫法:
const [state, setState] = useState(someExpensiveComputation(props));
否則,每次渲染都會執行 someExpensiveComputation(props)
useEffect
useEffect(didUpdate);
預設情況下,useEffect 會在每一個完整 render 結束後執行裡面的程式碼
useContext - useContext 筆記
useRef - useRef 筆記
效能優化:useMemo、useCallback 和 memo
useMemo
useMemo 主要用在記憶複雜的程式碼或運算出來的回傳值,如此,重新渲染時,除非 dependency 改變,否則不用再次執行運算。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
舉例來說:
function WithoutMemo() {
const [count, setCount] = useState(1);
const [val, setValue] = useState("");
function expensive() {
let sum = 0;
for (let i = 0; i < count * 100; i++) {
sum += i;
}
return sum;
}
return (
<div>
<h4>
{count}-{val}-{expensive()}
</h4>
<div>
<button onClick={() => setCount(count + 1)}>+c1</button>
<input value={val} onChange={(event) => setValue(event.target.value)} />
</div>
</div>
);
}
WithoutMemo 中有兩個 state,且每次渲染時都會執行 expensive 函式拿到某個值。然而,無論是修改 count 還是 val,都會重新渲染元件並觸法 expensive 的執行,但是,expensive 只和 count 值有關。在這種情況下,就可以使用 useMemo,只在 count 值修改時,執行 expensive 計算。
export default function WithMemo() {
const [count, setCount] = useState(1);
const [val, setValue] = useState("");
const expensive = useMemo(() => {
let sum = 0;
for (let i = 0; i < count * 100; i++) {
sum += i;
}
return sum;
}, [count]);
return (
<div>
<h4>
{count}-{val}-{expensive()}
</h4>
<div>
<button onClick={() => setCount(count + 1)}>+</button>
<input value={val} onChange={(event) => setValue(event.target.value)} />
</div>
</div>
);
}
useCallback
useCallback 跟 useMemo 很類似,但回傳的是已記憶的函式,除非 dependency 改變時才會重新渲染此函式
useCallback(fn, deps)等同於 useMemo(() => fn, deps)
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
React.memo
//兩個參數分別為
1. 需要做效能優化、比較props的元件
2. 自定義比較 props的方法
React.memo(CustomComponent, areEqual)
React.memo 是一個 high order component,當父層狀態改變,底下的每個子元件都會重新渲染,就算它依賴的 props 或 state 沒有改變。因此,React 提供了 memo,memo 會幫忙檢測 props 是否有變動,當 props 沒改變時, component 就不會重新渲染
。React.memo 是專用於 Component 的方法
memo 是利用淺層比較(shallowly compare) 的方法確認 props 的值是否一樣, 淺層比較 在 props 是基本資料型別時比較的是值(value),但當 props 是 Object 時,比較的卻是記憶體位置(reference)。