簡介
Hook是React 16.8的新增特性。它可以讓你在不編寫class的情況下使用state以及其他的React特性其實就是專門用于增強函數(shù)組件的功能的,使之盡可能的替代類組件而存在
本質(zhì)上是一個函數(shù)
(use...),可掛載任何功能僅在函數(shù)組件體內(nèi)生效
State Hook
useState(defaultState);參數(shù)為默認的
state值返回一個長度為
2的數(shù)組,第一項是state值,第二項為改變state值的函數(shù),const [count, setCount] = useState(0);狀態(tài)可以有多個
State Hook原理
函數(shù)組件的首次調(diào)用以及后續(xù)更新都會直接調(diào)用
use...函數(shù)React通過函數(shù)組件節(jié)點的狀態(tài)表格來保存state值,使其不會在每次組件函數(shù)調(diào)用時都會被初始化首次調(diào)用函數(shù)組件時這些
state值會被按順序保存在狀態(tài)表格中,每個state值都有一個固定且唯一的下標(biāo)值,從0開始更新函數(shù)組件時,將會忽略默認
state值,直接通過對應(yīng)下標(biāo)值找到狀態(tài)表格中所保存的值這也是
React解釋說為什么使用useState而不是createState命名的原因
State Hook注意點
useState不可寫在代碼塊之中,例如判斷,循環(huán)。因為這可能導(dǎo)致更新函數(shù)組件時,一些useState不被執(zhí)行之類的混亂情況,從而導(dǎo)致下標(biāo)值對應(yīng)錯誤,state被賦予不正確的值useState所返回的第二項函數(shù),引用不會改變,節(jié)省內(nèi)存-
set...函數(shù)的執(zhí)行會使函數(shù)組件重新渲染,也就是再次執(zhí)行函數(shù)若調(diào)用改變
state值的函數(shù)set...時state的值與之前的完全相同(使用Object.is判斷),則不會導(dǎo)致重新渲染調(diào)用改變
state值的函數(shù)set...會直接替換原先的值,而不是合并覆蓋,所以要注意引用值的使用,可使用...展開
函數(shù)組件內(nèi)的強制刷新可使用
const [, forceUpdate] = useState({});forceUpdate({});調(diào)用時發(fā)現(xiàn)對象地址不同,則會重新渲染該函數(shù)組件如果某些狀態(tài)之間并沒有什么必然的聯(lián)系,我們應(yīng)該將他們分開來寫,而不是混合到一個
state中和類組件相同,函數(shù)組件中的狀態(tài)改變?nèi)羰窃?
DOM事件中則是異步的,這種情況下多次調(diào)用狀態(tài)變化函數(shù)會被合并來提高效率若是想要在
DOM事件中多次調(diào)用狀態(tài)變化函數(shù),可以傳入一個函數(shù)作為參數(shù)setCount(prevC => prevC + 1); setCount(prevC => prevC + 1);這些函數(shù)會在
DOM事件結(jié)束時依次執(zhí)行,前一個函數(shù)的返回值作為后一個函數(shù)的參數(shù)
Effect Hook
用于在函數(shù)組件內(nèi)處理副作用
useEffect(),該函數(shù)接收一個函數(shù)參數(shù),函數(shù)內(nèi)部就是我們要執(zhí)行的副作用代碼
副作用
-
ajax請求,計時器,其他異步操作,更改真實DOM對象,本地存儲,其他會對外部產(chǎn)生影響的操作
Effect Hook注意點
副作用函數(shù)
(useEffect的函數(shù)參數(shù))的運行時間點,位于更改了真實DOM之后,且已經(jīng)完成重新渲染,也就是用戶已經(jīng)看到了頁面變化之后,所以是異步執(zhí)行,不會阻塞而類組件中的
componentDidMount以及componentDidUpdate的執(zhí)行時間點位于更改了真實DOM之后,但還未重新渲染,也就是用戶還未看到頁面變化之前useEffect在一個函數(shù)組件內(nèi)可多次使用,但不可寫入代碼塊之中,例如判斷,循環(huán)。與useState同理副作用函數(shù)可以有一個返回值,返回值必須為函數(shù)或默認的
undefined,該函數(shù)作用為清理遺留的副作用,例如計時器,運行時間點位于下次副作用函數(shù)運行之前,所以首次渲染組件不會運行,useEffect函數(shù)的第二個參數(shù)未變化時也不會運行,組件被銷毀時一定會運行-
useEffect函數(shù)可接受第二個數(shù)組參數(shù),數(shù)組中傳入該副作用函數(shù)內(nèi)的依賴數(shù)據(jù)當(dāng)組件重新渲染后,只有依賴數(shù)據(jù)與上次不同時,才會再次執(zhí)行副作用函數(shù)
所以若使用空數(shù)組作為
useEffect函數(shù)的第二個參數(shù),那么副作用函數(shù)僅在首次渲染結(jié)束后運行一次,清理函數(shù)也僅在卸載時運行一次
副作用函數(shù)中,若使用了組件函數(shù)
AO中的變量,則由于閉包的原因,會導(dǎo)致副作用函數(shù)中變量不會實時變化,而是使用所在的某次組件函數(shù)的調(diào)用時的變量
自定義Hook
將一些常用的,多個組件都會使用的
Hook功能,抽離出去寫成一個函數(shù),就叫做自定義Hook-
組件在使用自定義
Hook時就等同于將自定義Hook函數(shù)中的代碼拿出來放到該自定義Hook函數(shù)執(zhí)行的地方所以自定義
Hook中使用set...同樣會使自定義Hook函數(shù)本身以及使用她的函數(shù)組件都重新執(zhí)行一次并且執(zhí)行順序也是從函數(shù)組件開始,遇到自定義
Hook執(zhí)行就進入自定義Hook函數(shù)內(nèi)部執(zhí)行,執(zhí)行結(jié)束返回新的值賦值給接收的變量,最后就是函數(shù)組件剩余的代碼執(zhí)行
自定義
Hook必須以use開頭自定義
Hook中的state始終是獨立的,所以在兩個組件中使用相同的Hook也不會共享state
Context Hook
用于函數(shù)組件更輕松的獲取
context-
在消費組件中
const myContext = useContext(MyContext);
Callback Hook
返回一個僅根據(jù)依賴項變化而變化地址的函數(shù),常用于給純組件傳遞屬性方法
Memo Hook
返回第一個函數(shù)參數(shù)的返回值,僅在依賴項變化時才會再次執(zhí)行第一個函數(shù)參數(shù),返回一個新的值
常用于高開銷的計算操作
Ref Hook
讓函數(shù)組件重新執(zhí)行時不會又重新創(chuàng)建一個新的
ref也就是讓每個函數(shù)組件對象擁有一個固定不變的
ref通過
.current來獲取,不局限于獲取dom元素或組件對象