在了解React Hooks之前,我們必須先知道React的函數(shù)組件性質(zhì)以及的函數(shù)組件為什么要用Hooks。
大伙兒都知道,無組件不React,而React的組件又分為類式組件和函數(shù)式組件,為什么函數(shù)式組件大受React開發(fā)者的推廣?
首先我們從源碼的角度來簡(jiǎn)單談一下類式組件和函數(shù)式組件的區(qū)別:
定義類組件時(shí),我們必須繼承React.Component

同時(shí),它具有一個(gè)render函數(shù)

咱們見好就收,畢竟具體操作需要涉及源碼,不是一時(shí)半會(huì)解釋的清的。那么render加載組件時(shí),發(fā)生了什么?
1.根據(jù)組件標(biāo)簽,找到組件
2.由于是類式組件,創(chuàng)建新的實(shí)例,并通過該實(shí)例調(diào)用到原型上的render方法
3.將虛擬Dom轉(zhuǎn)化為真實(shí)DOM
類式組件被定義為復(fù)雜的組件,這不是React所希望的,React想要的組件是純函數(shù)組成的管道,那么便引出了作為簡(jiǎn)單組件的函數(shù)組件。
而函數(shù)組件作為一個(gè)函數(shù),是沒有繼承React.Component的,他只需要兩步1.找到組件 2.渲染組件,所以也就不存在生命周期,以及狀態(tài)及this。
這就意味著,函數(shù)組件實(shí)現(xiàn)有關(guān)state的管理,需要借助redux,秉承redux能不用就不用的準(zhǔn)則(其實(shí)有的時(shí)候還蠻香的,全局管理方便),往往會(huì)另功能簡(jiǎn)單的React組件變得笨重。
于是React團(tuán)隊(duì)自16.8版本以來,推出了穩(wěn)定的React HOOKS來解決上述問題。
React Hooks
React約定鉤子的前綴為use,所以需要自定義鉤子時(shí),一般使用use為前綴創(chuàng)建鉤子。除此之外,React默認(rèn)提供了四種鉤子:
1)useState
相當(dāng)于一種靜態(tài)聲明,目的是引入狀態(tài),此時(shí)的鉤子保存狀態(tài)。useState()接收函數(shù)狀態(tài)的初始值,具有兩個(gè)參數(shù),第一個(gè)為狀態(tài)變量,第二個(gè)為改變狀態(tài)的方法,比如const [number,setNumber] = useState(0)
2)useEffect
副作用鉤子,用來替代生命周期,最常見是向服務(wù)器請(qǐng)求數(shù)據(jù)

useEffect()作為常用的鉤子之一,接收兩個(gè)參數(shù),第一個(gè)參數(shù)是函數(shù),第二個(gè)參數(shù)是一個(gè)數(shù)組,給出依賴項(xiàng),數(shù)組里的值代表需要監(jiān)測(cè)的對(duì)象。
問題來了,生命周期那里體現(xiàn)?
當(dāng)組件參數(shù)發(fā)生改變時(shí),useEffect()就會(huì)執(zhí)行。組件第一次渲染時(shí),useEffect()也會(huì)執(zhí)行。是不是相當(dāng)于生命周期中的componentDidMount()呢?而useEffect()下的return,一般寫在第一個(gè)參數(shù)的異步操作后,相當(dāng)于componentWillUnmount(),在組件卸載前執(zhí)行,做收尾工作。
3)useReducer
屬于action鉤子,useReducer()將算出新的state,返回一個(gè)數(shù)組。例如const [state, dispatch] = useReducer(ReducerFunc, initState)
第一個(gè)值是當(dāng)前狀態(tài)值,第二個(gè)值是發(fā)送action的dispatch。與Redux的Reducer一樣,能夠共享狀態(tài),但是不同之處是沒法提供中間件和時(shí)間旅行(time travel)。
4)useContext
共享狀態(tài)的一個(gè)鉤子,在組件外部建立一個(gè)Context,包裹組件時(shí),可以將被包裹組件的狀態(tài)共享給組件內(nèi)部調(diào)用的其他組件,即:
1.外部建立Context()
2.包裹含有狀態(tài)的組件1
3.在其他函數(shù)組件內(nèi)部調(diào)用該Context()時(shí),可以將組件1的狀態(tài)共享
但是有一點(diǎn)需要注意的是,使用useContext進(jìn)行的數(shù)據(jù)流管理,每當(dāng)context更新時(shí),所有使用到該context的組件都會(huì)重新渲染。所以需要方法對(duì)useContext()進(jìn)行優(yōu)化,減少不必要的更新,優(yōu)化方法可以參考:如何優(yōu)雅地處理使用React Context 導(dǎo)致的不必要渲染問題?
除此之外還有一些自帶的鉤子,比如:
5)useCallback和useMemo
可以用做React性能優(yōu)化
react很煩,一但更新數(shù)據(jù),render依次diff刷新節(jié)點(diǎn),攔都攔不住。useCallback和useMemo就是攔住他刷新的方法。
假設(shè)React組件中有個(gè)button,同時(shí)聲明了click方法,每次render時(shí),button和click方法都會(huì)重新render。于是可以使用useCallback(),避免組件重復(fù)無意義的渲染。
比如:

原因是緩存了相同的引用,以此避免了無效render。
useMemo參數(shù)用法一致,不過useCallback一般用于緩存函數(shù),useMemo用于緩存計(jì)算結(jié)果之類。
useCallback(fn, deps)相當(dāng)于useMemo(()=>fn, deps)
*可以推出,使用useCallback實(shí)現(xiàn)useMemo的方法:
useMemo(fun,...deps)??
useCallback(fun(...deps), [...deps])
這兩者是等價(jià)的。
如果有不一樣的理解,有交流想法的朋友可以聯(lián)系私信,轉(zhuǎn)載請(qǐng)做好來源說明!