React 創建組件的方式:
- 類組件
- 函數式組件
a. 純函數組件沒有狀態
b. 純函數組件沒有生命周期
c. 純函數組件沒有this
d. 只能是純函數
這就注定,我們所推崇的函數組件,只能做 UI 展示的功能,涉及到狀態的管理與切換,我們不得不用類組件或者 redux。
Hook 就是 JavaScript 函樹,它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。
Hook 使用規則
只能在函數最外層調用 Hook。不要在循環、條件判斷或者子函數中調用。
確保總是在你的 React 函數的最頂層以及任何 return 之前調用他們。遵守這條規則,你就能確保 Hook 在每一次渲染中都按照同樣的順序被調用。這讓 React 能夠在多次的 useState 和 useEffect 調用之間保持 hook 狀態的正確。只能在 React 的函數組件、自定義的 Hook中調用 Hook。不要在其他 JavaScript 函數中調用。
常見 hooks
useState():返回一個 state,以及更新 state 的函數。
const [state, setState] = useState(initialState)
兩種傳參方式:
a. 直接傳入新值setState(state + 1)
b. 函數式更新setState((prevState) => prevState + 1)
-
useEffect():接收一個包含命令式、且可能有副作用代碼的函數
useEffect(() => { const subscription = props.source.subscribe(); return () => { // 清除 effect subscription.unsubscribe() } }[, arg])
不傳遞第二個參數:默認情況,effect 會在每輪組件渲染完成后執行,一旦組件重新 render,effect 都會被重新創建
第二個參數為空數組:effect 僅在組件掛載和卸載時執行
第三個參數為數組,即依賴項:一旦依賴發生變化,effect 就會被重新創建 useLayoutEffect()
它會在所有的 DOM 變更之后同步調用 effect。可以使用它來讀取 DOM 布局并同步觸發重渲染。在瀏覽器執行繪制之前,useLayoutEffect 內部的更新計劃將被同步刷新。userContext():
const value = useContext(MyContext)
接收一個 context 對象(React.createContext
的返回值)并返回該 context 的當前值。當前的 context 值由上層組件中距離當前組件最近的<MyContext.Provider>
的value
prop 決定。
當組件上層最近的<MyContext.Provider>
更新時,該 Hook 會觸發重渲染,并使用最新傳遞給MyContext
provider 的 contextvalue
值。
別忘記useContext
的參數必須是 context 對象本身:userReducer()
兩種不同初始化 useReducer state 的方式:
a. 指定初始 state:const [state, dispatch] = useReducer(reducer, initialState)
b. 惰性初始化:const [state, dispatch] = useReducer(reducer, initialArg, init)
,這樣初始 state 將被設置為 init(initialArg)-
useCallback():返回一個 memoized 回調函數。
把內聯回調函數及依賴項數組作為參數傳入useCallback
,它將返回該回調函數的 memoized 版本,該回調函數僅在某個依賴項改變時才會更新。const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], )
useMemo():
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
返回一個 memoized 值。把“創建”函數和依賴項數組作為參數傳入useMemo
,它僅會在某個依賴項改變時才重新計算 memoized 值。傳入useMemo
的函數會在渲染期間執行,請不要在這個函數內部執行與渲染無關的操作,如果沒有提供依賴項數組,useMemo
在每次渲染時都會計算新的值。
useCallback(fn, deps)
相當于useMemo(() => fn, deps)
useRef():
const refContainer = useRef(initialValue)
useRef 返回一個可變的 ref 對象,其.current
屬性被初始化為傳入的參數(initialValue)。返回的 ref 對象在組件的整個生命周期內持續存在。
當 ref 對象內容發生變化時,useRef
并不會通知你。變更.current
屬性不會引發組件重新渲染。
use-immer
- 安裝:
npm install immer use-immer
- 使用 useImmer:
返回一個 immer,以及更新 immer 的函數 setImemer。import { useImmer } from "use-immer" const [immer, setImemer] = useImmer({ name: "Ming", sex:'female' age: 18 }) setImemer(draft => { draft.age++; })
- 使用 useImmerReducer:
對 useReducer 進行了再次封裝。用法和 useReducer 一樣import React from "react" import { useImmerReducer } from "use-immer" const initialState = { count: 0 } function reducer(draft, action) { switch (action.type) { case "reset": return initialState case "increment": return void draft.count++ case "decrement": return void draft.count-- } } function Counter() { const [state, dispatch] = useImmerReducer(reducer, initialState) return ( <> Count: {state.count} <button onClick={() => dispatch({ type: "reset" })}>Reset</button> <button onClick={() => dispatch({ type: "increment" })}>+</button> <button onClick={() => dispatch({ type: "decrement" })}>-</button> </> ) }