什么是React Hook?
一個(gè)特殊的函數(shù),用于鉤入React的特性蓝角。
它鼓勵(lì)我們將通用邏輯封裝成Hook而不是工具函數(shù)邪铲,明確了通用工具函數(shù)和業(yè)務(wù)工具函數(shù)的邊界。
使用React Hook有些什么好處?
1:很好的解決了狀態(tài)邏輯復(fù)用難的問(wèn)題凿渊,避免了嵌套地獄的出現(xiàn)。
2:關(guān)注點(diǎn)分離柜某,代碼邏輯更為清晰。
3:避免了class不能很好優(yōu)化的問(wèn)題敛纲,如不能很好的壓縮喂击,熱重載不穩(wěn)定。
使用React Hook規(guī)則有哪些淤翔?
1:只能在頂層使用翰绊,目的是保證Hook在每一次渲染中都能按照相同的順序被調(diào)用。
2:只能在函數(shù)組件或者自義定Hook中調(diào)用旁壮。
React Hook是如何與組件關(guān)聯(lián)起來(lái)的监嗜?
react會(huì)保持對(duì)當(dāng)前渲染組件的追蹤,每一個(gè)組件內(nèi)部都有一個(gè)記憶單元格抡谐,用于存儲(chǔ)JS對(duì)象數(shù)據(jù)裁奇。當(dāng)你調(diào)用Hook時(shí)就讀取當(dāng)前Hook所在組件的記憶單元格里面的數(shù)據(jù)。
有哪些React Hook?
下邊我們來(lái)一一整理下這些Hook的用法以及每個(gè)Hook應(yīng)該注意的隱藏問(wèn)題麦撵!
1:useState
概述:
讓函數(shù)組件也可以維護(hù)自己的state刽肠。
用法:
const [state, setState] = useState(initialState);
setState()可以直接傳遞一個(gè)newState, 也可以傳遞一個(gè)函數(shù),可獲取前一狀態(tài)的值免胃。
如:setState((prevState) => {})
注意:
useState()不同于setState(), 它是狀態(tài)替換而不是狀態(tài)合并音五。
建議:
將獨(dú)立的Sate拆分開(kāi)來(lái),為什么羔沙?
原因一:useState的state是替換躺涝,不是合并,所以拆分開(kāi)來(lái)比較合理扼雏。
原因二:有助于關(guān)注點(diǎn)分離坚嗜,相關(guān)功能邏輯在一起,代碼清晰易觀诗充。
2:useEffect
概述:
它具有與componentDidMount惶傻、componentDidUpdate、componentWillUnmount三個(gè)生命周期鉤子相同的用途其障,它是他們?nèi)吆喜⒑蟮腁PI银室。
用法:
useEffect(() => {}, 可選數(shù)組參數(shù))
1:第一個(gè)參數(shù)為函數(shù),該函數(shù)內(nèi)部執(zhí)行的動(dòng)作相當(dāng)于componentDidUpdate和componentDidUpdate兩個(gè)生命周期中要干的事情,其結(jié)果返回一個(gè)函數(shù)蜈敢,該函數(shù)內(nèi)部定義的動(dòng)作相當(dāng)于componentWillUnmount生命周期時(shí)要干的事情 辜荠。但值得注意的是這個(gè)返回函數(shù)并不是在組件銷毀時(shí)候執(zhí)行的,事實(shí)上它會(huì)在我們每次重新渲染后被調(diào)用抓狭。為什么伯病?因?yàn)閡seEffect的執(zhí)行機(jī)制,每次我們重新渲染的時(shí)候都會(huì)生成新的effect用來(lái)替換掉之前的effect否过。所以某種意義上來(lái)說(shuō), effect更像是渲染結(jié)果的一部分午笛,每一個(gè)effect屬于一次特定的渲染。
2:第二個(gè)參數(shù)為可選參數(shù)苗桂,可能的值為空數(shù)組或者是具體依賴數(shù)組药磺。其作用是優(yōu)化重新渲染性能,相當(dāng)于我們生命周期中shouldComponentUpdate對(duì)觸發(fā)更新的依賴對(duì)象進(jìn)行淺比較然后來(lái)確定是否需要重新渲染更新煤伟。
2-1:當(dāng)省略這個(gè)參數(shù)的時(shí)候癌佩,相當(dāng)于setState后都要進(jìn)行更新。
2-2:當(dāng)為[]時(shí)便锨,只初始化執(zhí)行一次围辙,后邊不再進(jìn)行更新。
2-3:當(dāng)為具體的依賴對(duì)象數(shù)組時(shí)放案,具體的依賴對(duì)象有變化就更新重渲染姚建,沒(méi)變化就不更新重渲染。
3:useContext
概述:
接收一個(gè) context 對(duì)象(React.createContext?的返回值)并返回該 context 的當(dāng)前值吱殉。
它其實(shí)相當(dāng)于class組件中 static context = xxTheme桥胞。我理解為是獲取環(huán)境變量值的鉤子。
當(dāng)使用了該鉤子函數(shù)的組件最近一層的<MyContext.Provider>更新時(shí)考婴,該鉤子會(huì)觸發(fā)重新渲染贩虾。即使祖先使用了React.memo或者ShouldComponentUpdate,也會(huì)觸發(fā)重新渲染沥阱。
用法:
cons xxTheme = useContext(xxContext);
const xxContext = React.createContext("xxx");
4:useLayoutEffect
概述:
其函數(shù)簽名與?useEffect?相同缎罢,但它會(huì)在所有的 DOM 變更之后同步調(diào)用 effect】忌迹可以使用它來(lái)讀取 DOM 布局并同步觸發(fā)重渲染策精。在瀏覽器執(zhí)行繪制之前,useLayoutEffect?內(nèi)部的更新計(jì)劃將被同步刷新崇棠。
盡可能使用標(biāo)準(zhǔn)的?useEffect?以避免阻塞視覺(jué)更新咽袜。
5:useRef
概述:
它不僅可以用于DOM refs。它還是一個(gè)current屬性可變且可以容納任意值的通用容器枕稀,類似于class的實(shí)例屬性询刹。
用法:
const myRef = useRef(initialValue);
6:useCallback
概述:
把內(nèi)聯(lián)回調(diào)函數(shù)及依賴項(xiàng)數(shù)組作為參數(shù)傳入?useCallback谜嫉,它將返回該回調(diào)函數(shù)的 memoized 版本,該回調(diào)函數(shù)僅在某個(gè)依賴項(xiàng)改變時(shí)才會(huì)更新凹联。當(dāng)你把回調(diào)函數(shù)傳遞給經(jīng)過(guò)優(yōu)化的并使用引用相等性去避免非必要渲染(例如?shouldComponentUpdate)的子組件時(shí)沐兰,它將非常有用。useCallback(fn, deps)?相當(dāng)于?useMemo(() => fn, deps)蔽挠。
抽離useEffect中的公共邏輯時(shí)很有用住闯。
用法:
useCallback(fn, deps)?
7:useMemo
概述:
把“創(chuàng)建”函數(shù)和依賴項(xiàng)數(shù)組作為參數(shù)傳入?useMemo,它僅會(huì)在某個(gè)依賴項(xiàng)改變時(shí)才重新計(jì)算 memoized 值澳淑。這種優(yōu)化有助于避免在每次渲染時(shí)都進(jìn)行高開(kāi)銷的計(jì)算比原。
記住,傳入?useMemo?的函數(shù)會(huì)在渲染期間執(zhí)行杠巡。請(qǐng)不要在這個(gè)函數(shù)內(nèi)部執(zhí)行與渲染無(wú)關(guān)的操作量窘,諸如副作用這類的操作屬于?useEffect?的適用范疇,而不是?useMemo忽孽。
你可以把?useMemo?作為性能優(yōu)化的手段绑改,但不要把它當(dāng)成語(yǔ)義上的保證谢床。將來(lái)兄一,React 可能會(huì)選擇“遺忘”以前的一些 memoized 值,并在下次渲染時(shí)重新計(jì)算它們识腿,比如為離屏組件釋放內(nèi)存出革。先編寫(xiě)在沒(méi)有?useMemo?的情況下也可以執(zhí)行的代碼 —— 之后再在你的代碼中添加?useMemo,以達(dá)到優(yōu)化性能的目的渡讼。
用法:
useMemo(() => fn, deps)
8:useReducer
概述:
它其實(shí)是一個(gè)內(nèi)置的自定義Hook骂束。
當(dāng)你有個(gè)相當(dāng)復(fù)雜的組件包含了大量以特殊方式來(lái)管理的內(nèi)部狀態(tài),我們通常會(huì)使用redux三方庫(kù)來(lái)進(jìn)行管理成箫。但是如果此時(shí)你并不想引入三方庫(kù)展箱,那么自定義鉤子函數(shù)useReducer就會(huì)是一個(gè)很不錯(cuò)的選擇。
用法:
const [state, dispatch] = useReducer(reducer, initialArg, init);
具體實(shí)現(xiàn)參考官網(wǎng)自定義Hook
注意:
所謂惰性初始化蹬昌,就是將用于計(jì)算state的邏輯抽取到reducer外部混驰,這對(duì)未來(lái)重置state的action很有便利。
9:useImperativeHandle
概述:
在使用ref時(shí)自義定暴露給父組件的實(shí)例值皂贩。
它應(yīng)當(dāng)和forwardRef一起使用栖榨。
用法:
useImperativeHandle(ref, handle, [deps])
10:useDebugValue
概述:
useDebugValue?可用于在 React 開(kāi)發(fā)者工具中顯示自定義 hook 的標(biāo)簽。
用法:
useDebugValue(value)
如: useDebugValue(isOnline ? "online" : "offline")
11: 自定義Hook
概述:
2個(gè)或更多組件間公用邏輯部分抽取封裝成一個(gè)新的函數(shù)明刷,函數(shù)名以u(píng)se開(kāi)始婴栽,內(nèi)部可以調(diào)用其他Hook。
注意一:為什么要以u(píng)se開(kāi)頭辈末,這個(gè)約定主要是為了判斷該函數(shù)內(nèi)部是否使用了Hook調(diào)用愚争,方便自動(dòng)檢查Hook調(diào)用是否符合規(guī)范映皆。
注意二:兩個(gè)或多個(gè)組件內(nèi)部使用相同的自定義Hook不會(huì)共享state。自定義Hook只是一種重用狀態(tài)邏輯的機(jī)制准脂,從react的角度來(lái)看劫扒,我們的組件只是多次調(diào)用了useState和useEffect,它們是完全獨(dú)立的狸膏。