文章參考: Hook API 索引
普通Hook(常用)
useState、useEffect
useContext
前言:在一個典型的 React 應用中,數(shù)據(jù)是通過 props 屬性自上而下(由父及子)進行傳遞的,但這種做法對于某些類型的屬性而言是極其繁瑣的(例如:地區(qū)偏好,UI 主題),這些屬性是應用程序中許多組件都需要的。Context 提供了一種在組件之間共享此類值的方式,而不必顯式地通過組件樹的逐層傳遞 props。
創(chuàng)建一個Context對象,設置一個默認值Tom
const ThemeContext = React.createContext('Tom');
獲取Context對象的內(nèi)容,會向上找 Context.Provider的值
const theme = useContext(ThemeContext);
把如下代碼與 Context.Provider 放在一起
// Context 可以讓我們無須明確地傳遍每一個組件,就能將值深入傳遞進組件樹。
// 為當前的 theme 創(chuàng)建一個 context(“Tom”為默認值)。
const ThemeContext = React.createContext('Tom');
function App () {
// 使用一個 Provider 來將當前的 theme 傳遞給以下的組件樹。
// 無論多深,任何組件都能讀取這個值。
// 在這個例子中,我們將 “Jerry” 作為當前的值傳遞下去。
return (
<ThemeContext.Provider value="Jerry">
<Toolbar />
</ThemeContext.Provider>
);
}
// 中間的組件再也不必指明往下傳遞 theme 了。
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton () {
// 指定 contextType 讀取當前的 theme context。
// React 會往上找到最近的 theme Provider,然后使用它的值。
// 在這個例子中,當前的 theme 值為 “Jerry”。
const theme = useContext(ThemeContext);
render() {
return <Button theme={theme} />;
}
}
其他Hook (不常用)
useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
useState的替代方案。在state 邏輯較復雜且包含多個子值,或者下一個 state 依賴于之前的 state的情況下,useReducer 會比 useState 更適用
- reducer
它接收一個形如(state, action) => newState 的 reducer函數(shù),參數(shù)是當前的state值(state),和操作配置(action),最后返回一個新的state值 - initialArg
state的初始值 - init
這是一個可選值,可以用來惰性提供初始狀態(tài)。這意味著我們可以使用使用一個 init 函數(shù)來計算初始狀態(tài)/值,而不是顯式的提供值。如果初始值可能會不一樣,這會很方便,最后會用計算的值來代替初始值。
實現(xiàn)一個計數(shù)器
// 對初始值進行處理
function init(initialCount) {
return {count: initialCount};
}
// reducer函數(shù),根據(jù)action配置處理state值
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
case 'reset': return init(action.payload); default:
throw new Error();
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, initialCount, init);
return (
<>
Count: {state.count}
<button
onClick={() => dispatch({type: 'reset', payload: initialCount})}>
Reset
</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
【注】跳過 dispatch
如果 Reducer Hook 的返回值與當前 state 相同,React 將跳過子組件的渲染及副作用的執(zhí)行。(React 使用Object.is比較算法)
useReducer源碼解釋
// state的處理配置
function todosReducer(state, action) {
switch (action.type) {
case 'add':
return [...state, {
text: action.text,
completed: false
}];
// ... other actions ...
default:
return state;
}
}
// useReducer源碼
function useReducer(reducer, initialState) {
const [state, setState] = useState(initialState); // 設置staste,傳入初始值
function dispatch(action) { // useReaducer的第二個返回值,參數(shù)是state的配置對象
const nextState = reducer(state, action); // 調(diào)用傳入的state處理函數(shù),傳入state的初始值和配置,返回經(jīng)過處理的后的state值
setState(nextState); // 更新state值
}
return [state, dispatch]; // 返回設置的state值,和更新state的回調(diào)函數(shù)
}
const [todos, dispatch] = useReducer(todosReducer, []);
useCallback
useCallback(fn, deps) 相當于 useMemo(() => fn, deps)。
useMemo
返回一個 memoized 值。(memoization的技巧在于將計算過的結(jié)果『緩存』下來,避免重復計算帶來的成本)
把“創(chuàng)建”函數(shù)和依賴項數(shù)組作為參數(shù)傳入 useMemo,它僅會在某個依賴項改變時才重新計算 memoized 值。這種優(yōu)化有助于避免在每次渲染時都進行高開銷的計算。
傳入 useMemo 的函數(shù)會在渲染期間執(zhí)行。請不要在這個函數(shù)內(nèi)部執(zhí)行與渲染無關的操作,諸如副作用這類的操作屬于 useEffect 的適用范疇,而不是 useMemo。
如果沒有提供依賴項數(shù)組,useMemo 在每次渲染時都會計算新的值。
你可以把 useMemo 作為性能優(yōu)化的手段,但不要把它當成語義上的保證。將來,React 可能會選擇“遺忘”以前的一些 memoized 值,并在下次渲染時重新計算它們,比如為離屏組件釋放內(nèi)存。先編寫在沒有 useMemo 的情況下也可以執(zhí)行的代碼 —— 之后再在你的代碼中添加 useMemo,以達到優(yōu)化性能的目的。
useRef
useRef返回一個可變的 ref 對象
一個常見的用例便是命令式地訪問子組件:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已掛載到 DOM 上的文本輸入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
返回的ref對象,掛載到節(jié)點上,對象的指向就會變成該節(jié)點