--- tags: Note --- # 基礎 Hook ## useState useState 關注在狀態的改變 ### 寫法 ``` const [state, setState] = useState(default) ``` ### 說明 - state 代表原狀態,setState 代表改變後狀態,而 useState 後放預設值 - `useState` 會回傳一個包含兩個值的 array,第一個值是 state、第二個值是用來更新 state 的函式,**每當 state 值改變,就會觸發 re-render**,沒改變則不會 re-render。 - 可以宣告多個 state 變數 ### 還有這樣的區別 - Pass the state - 寫法 `setCount(count + 1)` - 每次都會重新跑(會覆蓋掉上次) - Pass the function - 寫法 `setCount(prev => prev + 1)` - 只跑第一次(不會覆蓋,建議都這樣寫) --- ## useEffect useEffect 用於非同步請求時 ### 寫法 ``` useEffect() => { ,[]} ``` ### 說明 - 任何會產生 side Effect 的行為都應該 Effect Hook 裡執行 - 跟 `componentDidMount`、`componentDidUpdate`、 `componentWillUnmount` 有著同樣的宗旨,但整合進一個單一的 API - **after rendering** 才會執行 - `useEffect` 的第二個參數 1. 什麼都不傳:render 後執行 2. 傳空陣列 `[]`:render 後只執行一次 3. 傳有變數的陣列 `[變數]`:render 後這個變數有改變才會執行 #### 副作用 side Effect 官方文件說明,副作用指我們曾在 React component 做過 fetch 資料、訂閱、或手動改變 DOM,這些操作就稱 side effect(簡稱 effect)因為他們可以影響其他 component 且在 render 期間無法完成。 --- ## useContext useContext 讓父子層之間不用手動一層一層傳遞 ### 寫法 ``` const value = useContext(MyContext); ``` ### 說明 - context 中的 `Provider` `consumer` 在 hook、class 中皆可使用 - useContext 的參數必需為 context object 自己 - ` useContext(MyContext)` 只能讀取 context 及訂閱其變更,還是要在 tree 的上層使用 `<MyContext.Provider>` 來提供 context 的值。 --- # 讓寫法優化的 Hook ## useMemo useMemo 根據改變的值重新計算結果,值沒改變則不觸發狀態改變 ### 寫法 ``` const check = useMemo(() => { let sum = 0; for(let i = 0; i<ocunt*100; i++) { sum +=1; } return sum; }, [count]); ``` ### 說明 - useMemo 再渲染時執行,不是渲染後(與 useEffect 區別),所以不建議做副作用相關操作 - `useMemo` 的第二個參數 1. 什麼都不傳:每次更新就重新計算 2. 傳空陣列 `[]`:只會計算一次 3. 傳有變數的陣列 `[變數]`:這個變數有改變才會重新計算 --- ## useCallback useCallback 是 useMemo 語法糖,能用 useCallback 實現的,都可以用 useMemo `useCallback(fn, deps)` 相當於 `useMemo(()=>fn,deps)` ### 寫法 ``` useCallback(fn, deps) = useMemo(() => fn, deps) ``` ![](https://i.imgur.com/9HAppoB.png) ### 說明 - 兩者差別,`useMemo` 調用且返回結果,`useCallback` 只返回結果 ### 情境 父子組件,子組件接收一個函數做為 props,一般父子組件會一起更新,但有時候子組件沒有更新必要,這時候使用 useCallback 來避免子組件不必要的更新。(借助 useCallback 返回函數,然後把這個函數作為 props 傳給子組件) --- ## useRef useRef 直接取到指定子層值 ### 寫法 ``` const refContainer = useRef(initialValue); ``` ### 說明 - 類似於類組件 `this.xxx` 寫法 --- ## useReducer useReducer 類似 redux 功能,比起 useState 適合寫更複雜邏輯且含多個子值 ### 寫法 ``` const [state, dispatch] = useReducer(reducer, initialArg, init); ``` ### 說明 - useReducer 的三個參數 1. reduce:類似`(state, action)=> newState` 的函數,傳上一個 state 跟本次的 action 2. state:初始狀態(默認值) ``` const [state, dispatch] = useReducer( reducer, {count: initialCount} ); ``` 3. 惰性初始化:將計算 state 的邏輯拿到 reducer 外,對之後重置 state 的 action 很方便 - 可以傳遞 dispatch 而不是 callback --- ## useLayoutEffect useLayoutEffect 裡的 callback 函数在 DOM 更新完成後立即執行,但是在瀏覽器渲染前執行完成,阻塞瀏覽器繪製 > 與 useEffect 結構相同,只是執行時機不同而已 ### 說明 - 與 useEffect 不同之處 — 執行時間 - DOM 更新 -> render -> useEffect - DOM 更新 -> useLayoutEffect -> render --- ## useImperativeHandle useImperativeHandle 可以讓使用 ref 時能向父 component 暴露自定義的 instance 值 ### 寫法 ``` useImperativeHandle(ref, createHandle, [deps]) ``` --- ## useDebugValue useDebugValue 可以用來在 React DevTools 中顯示自訂義 hook 的標籤 ### 寫法 ``` useDebugValue(value) ``` ### 說明 - 不建議在每個自定義 Hook 都加上 debug 值,它在自定義 Hook 的共享函式庫中才是最有價值的 --- ### 自定義 Hook 當我們想重用相同邏輯的組件時,可以自己寫一個 Hook --- 資料來源 - [React Doc](https://zh-hant.reactjs.org/docs/hooks-reference.html) - [hook 大全](https://blog.csdn.net/qq_41064597/article/details/119175873) - [hannah hook](https://medium.com/hannah-lin/react-hook-%E7%AD%86%E8%A8%98-%E5%BE%9E%E6%9C%80%E5%9F%BA%E6%9C%AC%E7%9A%84-hook-%E9%96%8B%E5%A7%8B-usestate-useeffect-fee6582d8725)