一. 基礎鉤子
(1)useState
用于在函數組件中添加局部狀態。useState可以傳遞一個參數,做為狀態的初始值
,返回一個數組,數組的第一個元素是返回的狀態變量,第二個是修改狀態變量的函數
。
const [state, setState] = useState(initalState); // 初始化,state可以任意命名setState(newState); // 修改state的值
(2)useEffect
處理副作用(如數據獲取、訂閱、手動 DOM 操作等)。若一個函數組件中定義了多個useEffect,那么他們實際執行順序是按照在代碼中定義的先后順序來執行的。?useEffect可以傳入2個參數:
-
?第1個參數是定義的執行函數,組件掛載和更新就會執行。
-
第2個參數是依賴關系(可選參數),如果不傳則每次渲染都會去執行,傳值的話在依賴項發生改變時函數中的代碼才會執行,如果傳空數組則會在組件第一次掛載才會執行。? ? ?
-
return 出去的代碼會在組件卸載時才會執行。
useEffect(() => {// 此處編寫 組件掛載之后和組件重新渲染之后執行的代碼...return () => {// 此處編寫 組件即將被卸載前執行的代碼...}
}, [dep1, dep2 ...]); // 依賴數組
(3)useContext
讀取 React 的上下文(Context)值。useContext 可以避免多層 props 傳遞就能共享狀態。具體用法看下面步驟:
先封裝一個js,里面可以設置初始值,這個初始值,可以在任何地方使用:
?
import React from 'react';
const UserContext = React.createContext( { name: '張三' }); //參數是默認值,可填可不填
export default UserContext;
? 在代碼中引用封裝好的js文件
import React, { useContext } from 'react'
import UserContext from './context';function Demo() {
// 如果React.createContext沒有指定默認值,可以在對應子組件上套上UserContext.Provider來指定值return (<UserContext.Provider value={{ name: '張三' }}><Child /></UserContext.Provider>)
}function Child() {const user = useContext(UserContext);return (<div><p>{`name: ${user.name}`}</p></div>)
}export default Demo;
二. 性能優化鉤子
(1)useMemo
緩存計算結果,避免重復計算(類似 Vue 的?computed
)。useMemo 可以傳入2個參數,第1個參數為函數,用來進行一些計算,第2個參數是依賴關系(可選參數),返回值為第一個函數 return 出去的值,只有在依賴項發生變化時才會重新執行計算函數進行計算,如果不傳依賴項,每次組件渲染都會重新進行計算。
-
useMemo
在組件頂層調用 -
useMemo
不能在事件處理函數、循環或條件語句中調用
const memoizedValue = useMemo(() => {// 計算邏輯...return res;
}, [a, b]);
(2)useCallback
緩存函數,避免子組件不必要的重渲染。
function Parent() {// 不使用 useCallback - 每次渲染都會導致 Child 重新渲染const handleClick = () => { /*...*/ };// 使用 useCallback - 避免 Child 不必要的重新渲染const handleClick = useCallback(() => {/*...*/}, []); // 空依賴表示函數永不變化return <Child onClick={handleClick} />;
}
(3)useTransition
?(React 18+)
標記非緊急更新,優化渲染優先級(如搜索框輸入時的延遲渲染)。
const [isPending, startTransition] = useTransition();
(4)useDeferredValue
?(React 18+)
延遲更新某些值,避免界面卡頓(如大型列表渲染)。
const deferredValue = useDeferredValue(value);
3. 引用與 DOM 操作
(1)useRef
可以獲取 dom 和 react 組件實例
。
import { useRef } from 'react'function Demo() {const inputRef = useRef();const handleFocus = () => {inputRef.current.value = 'focus';inputRef.current.focus();}return (<div><input ref={inputRef} /></div>)
}export default Demo;
(2)useImperativeHandle
自定義暴露給父組件的 ref 實例(通常配合?forwardRef
?使用)。父組件通過ref.current.getValue()獲取子組件中的value值。
const RichTextEditor = forwardRef((props, ref) => {const [value, setValue] = useState('');useImperativeHandle(ref, () => ({getValue: () => value,}));return (...);
})export default RichTextEditor;
4. 其他鉤子
(1)useReducer
復雜狀態邏輯管理(類似 Redux 的 reducer)。
// 代碼示例
import React, { useReducer } from 'react'// 1.需要有一個 reducer 函數,第一個參數為之前的狀態,第二個參數為行為信息
function reducer(state, action) {switch (action) {case 'add':return state + 1;case 'minus':return state - 1;default:return 0;}
}function Demo() {// 2.引入useReducer,第一個參數時上面定義的reducer,第二個參數時初始值// 3.返回為一個數組,第一項為狀態值,第二項為一個 dispatch 函數,用來修改狀態值const [count, dispatch] = useReducer(reducer, 0);return (<div><button onClick={() => { dispatch('add') }} >add</button><button onClick={() => { dispatch('minus') }} >minus</button><button onClick={() => { dispatch('unknown') }} >unknown</button><p>{`count: ${count}`}</p></div>);
}export default Demo;
(2)useLayoutEffect
類似?useEffect
,但會在 DOM 更新后同步執行(適合測量 DOM 布局)。useLayoutEffect 使用方法、所傳參數和 useEffect 完全相同。大多數情況下將 useEffect 替換成 useLayoutEffect 完全看不出區別。
唯一區別就是:使用 useEffect 時,頁面掛載會出現閃爍。而使用 useLayoutEffect 時頁面沒有閃爍,是因為 useEffect 是在頁面渲染完成后再去更新數據的,所以會出現短暫的閃爍,而 useLayoutEffect 是在頁面還沒有渲染時就將數據給更新了,所以沒有出現閃爍。
注意:大部分情況用useEffect就足夠了,useLayoutEffect 會阻塞渲染,所以需要小心的使用。
(3)useDebugValue
在 React 開發者工具中為自定義鉤子添加標簽。
useDebugValue(value, formatFn);
(4)useId
?(React 18+)
生成唯一 ID,用于無障礙訪問(a11y)或表單關聯。
const id = useId();
三.使用場景總結
鉤子 | 用途 |
---|---|
useState | 管理組件內部狀態 |
useEffect | 處理副作用(API 調用、訂閱等) |
useContext | 跨組件共享狀態 |
useMemo /useCallback | 優化性能,避免重復計算/渲染 |
useRef | 操作 DOM 或保存可變值 |
useReducer | 復雜狀態邏輯 |