一栅葡、解決了什么問題茉兰?
Hook 是以 use
開頭的特殊函數(shù)(useState、useEffect等)欣簇,只能在 函數(shù)組件 內(nèi)部使用规脸。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。譬如 useState 就等同于 class組件中的state對象熊咽。
1莫鸭、庫的更新說明
Hook是React 16.8 新增特性, 在以下模塊中包含了 React Hook 的穩(wěn)定實現(xiàn):
React DOM
React Native
React DOM Server
React Test Renderer
React Shallow Renderer
React Native 0.59 及以上版本支持 Hook横殴。
請注意被因,要啟用 Hook,所有 React 相關(guān)的 package 都必須升級到 16.8.0 或更高版本衫仑。如果你忘記更新諸如 React DOM 之類的 package梨与,Hook 將無法運(yùn)行。
二文狱、Hook 規(guī)則與插件
1粥鞋、規(guī)則
- Hook只能用在React 的函數(shù)組件和自定義Hook中。
- Hook只能在函數(shù)最外層調(diào)用 瞄崇,在循環(huán)呻粹、條件判斷或者子函數(shù)中調(diào)用都是不允許的。
2苏研、插件
eslint-plugin-react-hooks
用于檢查Hook代碼是否符合規(guī)則的插件等浊。
npm install eslint-plugin-react-hooks
3、插件鏈接:
我們推薦啟用 eslint-plugin-react-hooks
中的 exhaustive-deps
規(guī)則楣富。此規(guī)則會在添加錯誤依賴時發(fā)出警告并給出修復(fù)建議凿掂。
三伴榔、State Hook
State Hook 就是指 useState
這個特殊函數(shù)纹蝴,讓你不用編寫class庄萎,就可以使用state特性,換言之就是讓 函數(shù)組件 擁有 state 特性塘安。詳細(xì)用法糠涛,看這里!
四兼犯、Effect Hook
Effect Hook 就是指 useEffect
這個特殊函數(shù)忍捡,它讓 函數(shù)組件 能在組件渲染完成后執(zhí)行自定義操作。詳細(xì)用法切黔,看這里砸脊!
五、自定義Hook
自定義 Hook 是一個以 use
開頭的自定義函數(shù)纬霞,其內(nèi)部可以調(diào)用 Hook凌埂。
1、自定義Hook
import { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
2诗芜、使用自定義Hook
const friendList = [
{ id: 1, name: 'Phoebe' },
{ id: 2, name: 'Rachel' },
{ id: 3, name: 'Ross' },
];
function ChatRecipientPicker() {
const [recipientID, setRecipientID] = useState(1);
const isRecipientOnline = useFriendStatus(recipientID);
return (
<>
<Circle color={isRecipientOnline ? 'green' : 'red'} />
<select
value={recipientID}
onChange={e => setRecipientID(Number(e.target.value))}
>
{friendList.map(friend => (
<option key={friend.id} value={friend.id}>
{friend.name}
</option>
))}
</select>
</>
);
}
六瞳抓、Context Hook
Context Hook 就是指 useContext
這個特殊函數(shù),解決了 props 在特殊場景下傳遞數(shù)據(jù)的煩惱伏恐。詳細(xì)用法孩哑,看這里!
七翠桦、useReducer
useReducer 是 useState 的升級版本横蜒,對 setState 這個操作進(jìn)行了拆分,可以根據(jù)不同類型秤掌,進(jìn)行不同的邏輯計算愁铺,最后去改變 state 對象。詳細(xì)用法闻鉴,看這里茵乱!
八、useLayoutEffect
useLayoutEffect 的使用與 useEffect 一樣孟岛,只是被調(diào)用的時間點不同瓶竭。useEffect 是在瀏覽器繪制完成后被調(diào)用,useLayoutEffect 在瀏覽器繪制前被調(diào)用渠羞。
九斤贰、useDebugValue
在 React 開發(fā)者工具中顯示自定義 hook 的標(biāo)簽。
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// 在開發(fā)者工具中的這個 Hook 旁邊顯示標(biāo)簽
// e.g. "FriendStatus: Online"
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
// 第二個參數(shù)可以增加調(diào)試輸出信息
useDebugValue(date, date => date.toDateString());
十次询、useCallback
設(shè)置一個回調(diào)函數(shù)荧恍,只有當(dāng)依賴項的數(shù)值改變時,回調(diào)函數(shù)才被調(diào)用。如下送巡,只有依賴項數(shù)組 [a,b]
有變動時摹菠,才會調(diào)用箭頭函數(shù)。性能優(yōu)化時骗爆,去除一些非必要的組件渲染次氨。
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
【備注】 useCallback(fn, deps)
相當(dāng)于 useMemo(() => fn, deps)
。
十一摘投、useMemo
把箭頭函數(shù) 和 數(shù)組[a,b]煮寡,作為參數(shù)傳遞給 useMemo ,當(dāng)數(shù)組 [a,b] 的數(shù)值發(fā)生改變后犀呼,會在渲染期間調(diào)用箭頭函數(shù)幸撕。如果沒有第二個參數(shù)[a,b],那么每次渲染期間都會調(diào)用箭頭函數(shù)外臂。
先編寫在沒有 useMemo
的情況下也可以執(zhí)行的代碼 —— 之后再在你的代碼中添加 useMemo
杈帐,以達(dá)到優(yōu)化性能的目的。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
【備注】 useCallback(fn, deps)
相當(dāng)于 useMemo(() => fn, deps)
专钉。
React.memo
等效于 PureComponent
挑童,但它只比較 props。(你也可以通過第二個參數(shù)指定一個自定義的比較函數(shù)來比較新舊 props跃须。如果函數(shù)返回 true站叼,就會跳過更新。)
React.memo
不比較 state菇民,因為沒有單一的 state 對象可供比較尽楔。但你也可以讓子節(jié)點變?yōu)榧兘M件。
十二第练、useImperativeHandle
// 把自己暴露給父組件阔馋,供父組件操作訪問自己內(nèi)部。
useImperativeHandle(ref, createHandle, [deps])
useImperativeHandle 應(yīng)當(dāng)與 forwardRef 一起使用:
// input 把自己暴露給父組件娇掏,父組件就可以調(diào)用其 focus 方法呕寝。
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
渲染 <FancyInput ref={inputRef} /> 的父組件可以調(diào)用 inputRef.current.focus()。