解讀useState第二個參數(shù)的"第二個參數(shù)"
場景引入
在學習react的過程中,為了希望能使用hook養(yǎng)成寫函數(shù)式組件的習慣,我在完成日常作業(yè)的過程中刻意的使用hook,但也發(fā)現(xiàn)了幾個兩類組件里需要注意的問題。
先上一個需求場景:
當我們在類式組件中連續(xù)調(diào)用setState時,因為setState方法是異步的,所以即使執(zhí)行到第三個setState方法時,count仍為初始值0,所以其實執(zhí)行了三次setState,分別將count改為了1、2和3,但是因為最后一個方法覆蓋了之前的state,所以count為3。
類式組件
參數(shù)傳遞回調(diào)函數(shù)
在類式組件中,如果我們希望使我們需要的三個setState方法都起我們想到的作用,最先想到的就是我們選擇setState中參數(shù)的另一種傳遞方式——回調(diào)函數(shù):
我們可以在此回調(diào)函數(shù)中收集到一個保存之前一次state的參數(shù),這樣雖然setState方法仍然是異步執(zhí)行,但是當其執(zhí)行的時候每次都能取到上一次的state并在此基礎(chǔ)上做更新,可以達到我們想要的效果。
setState完成后執(zhí)行的回調(diào)函數(shù)
另一種方式是采用setState的第二個參數(shù)——state改變后的回調(diào)函數(shù):
這里要注意細節(jié)是不能提前解構(gòu)賦值,這樣只會取到第一次解構(gòu)出來的初始值0。
但是這樣的寫法無疑是很難看的,寫的多了就會形成回調(diào)地獄,使得代碼可讀性下降。
參數(shù)傳遞回調(diào)函數(shù)_promise版
為了解決回調(diào)地獄,很自然而然就想到使用promise做封裝:
將按鈕的回調(diào)函數(shù)變成異步函數(shù),并把每一個setState方法用promise封裝(因為await關(guān)鍵字只能等待promise),然后我們在state更改成功的回調(diào)里使用resolve放行,以此來模擬一個同步的場景。
函數(shù)式組件
說完了類式組件,我們調(diào)過頭來使用hook來對我們的需求進行重構(gòu)。
首先是使用useState的hook對組件進行重構(gòu),當然僅僅做改寫肯定是沒辦法達到我們的需求的。
參數(shù)傳遞回調(diào)函數(shù)
于是立馬使用useState的第二個參數(shù),也就是操作數(shù)組的方法,將其寫為一個回調(diào)函數(shù),目的和類式組件一致,是為了拿到前一次的state:
那我們?nèi)匀缓茏匀坏木拖霃涂填愂浇M件中setState的第二個參數(shù)——也就是傳遞一個state成功修改的回調(diào)函數(shù)的方法,這樣我們的分享也可以到此結(jié)束了。
利用useEffect監(jiān)聽count的變化
可惜useState中提供的修改state的方法并沒有提供這個回調(diào)函數(shù),意味著useState的第二個參數(shù)并沒有這么個“第二個參數(shù)”。
我們只好引入第二個hook:useEffect。
useEffect和類式組件中的生命周期有關(guān)系但并非完全有關(guān)系,我們時常通過監(jiān)聽一個空數(shù)組來模擬componnetDidMount生命周期,這里我們直接對count數(shù)據(jù)進行監(jiān)聽(類似vue中的watcher方法)。
當我們監(jiān)控到了count的改變后重新調(diào)用按鈕點擊回調(diào)事件,但是這也容易造成死循環(huán):回調(diào)函數(shù)改變數(shù)據(jù),數(shù)據(jù)修改再次調(diào)用回調(diào)。
所以我們要設(shè)置好跳出條件,我們?yōu)榱藢崿F(xiàn)+1+2+3的方法甚至不惜再使用一個useState,其實寫到這里我們已經(jīng)覺得就實現(xiàn)這個需求而言已經(jīng)不是一個很好的方法了。
那我們是不是可以再用promise進行包裝呢?
答案是可以!
async_await
這一塊其實是繞了一些彎子的,我們用promise進行一層包裝后,發(fā)現(xiàn)沒有第二個參數(shù)供我們調(diào)用resolve,于是我們想到把resolve拋出,當監(jiān)聽到count的變化的時候再執(zhí)行resolve放行,同時把監(jiān)聽到的count作為參數(shù)傳給下一個then方法,這個then方法再次返回一個新的promise并拋出一個新的resolve,當然我們最后也可以打印一下函數(shù)看看我們綁定在函數(shù)上的這兩個resolve方法。
當然還是不建議這么去做的,很明顯我們這種思路更多是為了強行去利用同步思想,在此作為一種思路擴展。
總結(jié)
此處再提出一些思路供大家思考:
1、能否用setTimeout等方法包裹一下setState執(zhí)行順序呢?本質(zhì)思路其實是異步任務(wù)的執(zhí)行順序?qū)哟蔚乃伎剂恕?/p>
2、能否手寫一個帶回調(diào)函數(shù)的useState呢?可以借助useRef。
這些僅為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
React Native中的RefreshContorl下拉刷新使用
本篇文章主要介紹了React Native中的RefreshContorl下拉刷新使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10React?Hook?Form?優(yōu)雅處理表單使用指南
這篇文章主要為大家介紹了React?Hook?Form?優(yōu)雅處理表單使用指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03react-redux action傳參及多個state處理的實現(xiàn)
本文主要介紹了react-redux action傳參及多個state處理的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07React中使用TS完成父組件調(diào)用子組件的操作方法
由于在項目開發(fā)過程中,我們往往時需要調(diào)用子組件中的方法,這篇文章主要介紹了React中使用TS完成父組件調(diào)用子組件,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07react-redux中connect的裝飾器用法@connect詳解
這篇文章主要介紹了react-redux中connect的裝飾器用法@connect詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01Reactjs?+?Nodejs?+?Mongodb?實現(xiàn)文件上傳功能實例詳解
今天是使用?Reactjs?+?Nodejs?+?Mongodb?實現(xiàn)文件上傳功能,前端我們使用?Reactjs?+?Axios?來搭建前端上傳文件應(yīng)用,后端我們使用?Node.js?+?Express?+?Multer?+?Mongodb?來搭建后端上傳文件處理應(yīng)用,本文通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧2022-06-06