精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Antd Mobile 作者教你寫 React 受控組件和非受控組件

開發(fā) 前端
在這篇文章,我們將一起聊聊怎么去讓一個(gè)組件像 antd 的 Input 組件這樣,既支持受控模式,又支持非受控模式。讓我們從最簡單和基礎(chǔ)的部分出發(fā),一點(diǎn)點(diǎn)來分析和演進(jìn),看看會(huì)遇到哪些問題,又如何一步步解決。

曾經(jīng),我每次面試時(shí)幾乎都會(huì)問一個(gè)問題:antd 中的 Input 組件是受控組件還是非受控組件?

有些人會(huì)毫不猶豫的回答:是受控組件,因?yàn)橛?nbsp;value 和 onChange,而另外也有一些人會(huì)比較猶豫,因?yàn)榈拇_似乎說 Input 是受控組件或非受控組件都說得過去。當(dāng)然,實(shí)際上 Input 組件既可以是受控組件,也可以是非受控組件,這完全取決于業(yè)務(wù)項(xiàng)目中怎么去使用它。

在這篇文章,我們將一起聊聊怎么去讓一個(gè)組件像 antd 的 Input 組件這樣,既支持受控模式,又支持非受控模式。讓我們從最簡單和基礎(chǔ)的部分出發(fā),一點(diǎn)點(diǎn)來分析和演進(jìn),看看會(huì)遇到哪些問題,又如何一步步解決。

什么是受控組件?什么又是非受控組件?

讓我們先來看一個(gè)簡單的例子,這個(gè) Input 組件有一個(gè)內(nèi)部的狀態(tài)(State)value,而且它沒有任何屬性,因此很顯然,它是一個(gè)非受控的組件,它的組件狀態(tài)并不受外部環(huán)境控制,而是封閉在組件內(nèi)部。

圖片圖片

而如果我們稍微對(duì)它做一點(diǎn)調(diào)整,把原本的內(nèi)部狀態(tài) value? 去掉,放到 props 上去,它就變成了受控組件:

圖片圖片

很顯然,此時(shí)輸入框的值是取決于外部傳遞進(jìn)來的 props。

如果我們畫個(gè)圖,那可以很清楚的看到受控和非受控的區(qū)別:

圖片圖片

圖中藍(lán)色的方框表示組件,黃色的圓圈表示組件內(nèi)的狀態(tài)。

既受控組件又非受控?

盡管在業(yè)務(wù)項(xiàng)目中,我們寫的組件都是明確的受控或者非受控,但對(duì)于組件庫來說,有非常多的組件需要做到既支持受控模式,又支持非受控模式。以 antd-mobile 現(xiàn)在的 5.17 版本為例,幾乎全部的涉及到輸入值、切換、展開收起的組件,都是需要做到既受控又非受控的。

盡管聽起來似乎不難,但實(shí)際寫起來還是會(huì)遇到一些困難的,讓我們來試一試。

如何實(shí)現(xiàn)

最簡單的方案:內(nèi)外兩個(gè)狀態(tài),手動(dòng)同步

考慮到實(shí)現(xiàn)成本的復(fù)雜度,我們需要讓組件邏輯在兩種模式下,盡可能的保持一致,減少邏輯分支意味著更好的可維護(hù)性和可讀性。所以,自然而然的,我們可以很容易想到這個(gè)方案:

Child 組件內(nèi)部始終存在一個(gè)狀態(tài),不管它處于哪種模式,它都直接使用自己內(nèi)部的狀態(tài)。而當(dāng)它處于受控模式時(shí),我們讓它的內(nèi)部狀態(tài)和 Parent 組件中的狀態(tài)手動(dòng)保持同步。

下面的示意圖中加上了兩個(gè)對(duì)勾標(biāo)記,被勾選的狀態(tài)表示 Child 組件實(shí)際在使用哪個(gè)狀態(tài)。?

圖片圖片

這套方案聽起來是可行的,我們把它寫成代碼:

圖片

仔細(xì)看上面的代碼,我們會(huì)發(fā)現(xiàn)在受控模式下存在兩個(gè)問題:

  1. ?原子性:Child 內(nèi)部狀態(tài)的更新會(huì)比 Parent 組件晚一個(gè)渲染周期,存在 tearing 的問題。
  2. 性能:因?yàn)槭窃趗seEffect? 中通過setState 來做的狀態(tài)同步,所以會(huì)額外的觸發(fā)一次渲染,存在性能問題。

明確問題之后,我們來逐個(gè)解決:

解決問題 1:原子性

這個(gè)問題其實(shí)很好解決,我們其實(shí)并不需要 Child 和 Parent 的狀態(tài)保持非常嚴(yán)格的每時(shí)每刻都一致,我們只需要判斷,如果組件此時(shí)處于受控模式,那么直接使用來自外部的狀態(tài)就可以了:

圖片

這樣,即便狀態(tài)的同步是存在延遲的,但是 Child 組件所真正使用到的值一定是最新的。

代碼如下:

圖片圖片

解決問題 2:性能

因?yàn)槲覀兪窃?nbsp;useEffect 去做狀態(tài)同步的,所以自然會(huì)額外的多觸發(fā)一次 Child 組件的重渲染。如果 Child 組件比較簡單的話,那出現(xiàn)的性能影響可以忽略不計(jì)。但是對(duì)于一些復(fù)雜的組件(例如 Picker),多渲染一次帶來的性能問題是比較嚴(yán)重的。

那有沒有辦法在 Child 組件的 render 階段就直接更新 value 狀態(tài)呢?

并不可以,React 不允許我們在 render 過程中調(diào)用 setState。

似乎進(jìn)入了死胡同,但我們可以停下來,重新考慮一下這行 useState 的代碼:

圖片圖片

當(dāng)我們創(chuàng)建這個(gè) State 時(shí)?我們的目的是什么?State 的本質(zhì)是什么?

如果比較簡單粗暴的分析,我們可以把 State 拆成兩部分:

  1. State 是用來存放數(shù)據(jù)的,它讓我們在組件的渲染函數(shù)之外,可以“持久化”一些數(shù)據(jù)。
  2. State 的更新可以觸發(fā)重新渲染,因?yàn)?React 會(huì)感知 State 的更新。

如果寫一個(gè)公式的話,可以寫成:

State = 存放數(shù)據(jù) + 觸發(fā)重新渲染

而但就存放數(shù)據(jù)來看,我們可以直接使用 Ref;同樣,如果只是需要觸發(fā)重新渲染,我們可以使用類似于 setFlag({}) 或者 setCount(v => v + 1) 這樣的強(qiáng)制方式(雖然很蠢,但想必 90% 的 React 開發(fā)者都曾經(jīng)這么寫過)。

那我們根據(jù)這個(gè)推斷來調(diào)整一下上面的公式:

State = Ref + forceUpdate()

我們已經(jīng)非常接近了,根據(jù)這個(gè)公式,我們可以把 Child 組件中的 State 拆成一個(gè) Ref 和一個(gè) forceUpdate 函數(shù):

下圖中的虛線淺色圓圈表示 ref,刷新圖標(biāo)表示 forceUpdate 函數(shù)”。

圖片圖片

這樣一來,我們就可以直接在 render 階段直接更新 ref 的值了:

圖片圖片

再回頭看下代碼,會(huì)發(fā)現(xiàn),為什么還需要判斷根據(jù)受控和非受控模式來使用不同的值呢?(上面代碼塊中的第 12 行)。既然 stateRef.current 一定是最新的值,那么完全可以簡化成 Child 組件永遠(yuǎn)使用內(nèi)部存放的數(shù)據(jù)(Ref):

圖片

除此之外,我們還可以把手動(dòng)實(shí)現(xiàn)的 forceUpdate 替換成 ahooks 的 useUpdate:

圖片

抽象與復(fù)用:usePropsValue

到這里,我們已經(jīng)基本實(shí)現(xiàn)了所有的功能,但我們只是實(shí)現(xiàn)了一個(gè) Input 組件,在 antd-mobile 這樣的組件庫中,會(huì)有很多很多組件都需要支持能夠切換受控和非受控模式。所以,為了更好的可復(fù)用性,我們把上面的邏輯抽離成一個(gè)自定義 Hook:

圖片圖片

這樣,在各種組件中,我們可以直接使用 usePropsValue,用法和 useState 非常接近:

圖片圖片

不過,我們忽略了 defaultValue,在 antd-mobile 中,value onChange defaultValue 總是成組出現(xiàn)的:

圖片圖片

接下來,讓我們對(duì)它再做一點(diǎn)優(yōu)化,讓它變得更像 useState。useState 得到的 setState 函數(shù),支持傳入一個(gè)更新函數(shù),而 usePropsValue 目前還不支持這種用法,所以我們來改造一下:

圖片圖片

一個(gè)隱藏的小 bug

我本以為已經(jīng)完工了,直到某天在 GitHub 上收到了一條 issue:TabBar 的 onChange 為什么在同 key 的情況也會(huì)觸發(fā) #5409[1]。

這條 issue 揭示了一個(gè)隱藏已久的 bug,舉個(gè)例子:

假如當(dāng)前的 state 為 1,如果我們用的是 React 的 useState,那執(zhí)行 setState(1) 不會(huì)有任何效果,React 會(huì)幫我們過濾掉這次的更新。而 usePropsValue 不會(huì)。

對(duì)用戶來說,點(diǎn)擊同一個(gè) Tab 并沒有觸發(fā)切換,也因此不應(yīng)該觸發(fā) onChange 事件,所以我們還需要額外的增加一點(diǎn)判斷,來解決這個(gè) bug:

圖片

在 antd-mobile 中,我們也有一個(gè)這樣的 usePropsValue 工具 Hook,和上面文章中所描述的幾乎是一樣的,如果你想了解更多,可以去這里[2]翻閱代碼。

勘誤

上面“解決問題 2:性能”章節(jié)中提到“React 不允許我們在 render 過程中調(diào)用 setState”,但經(jīng)評(píng)論區(qū)@fenoob[3]。

指正,其實(shí)是 React 是允許我們在 render 函數(shù)中調(diào)用 setState 的,只是限制了只能觸發(fā)當(dāng)前組件自己的 state 更新。我在這里寫了一個(gè) demo[4] 驗(yàn)證了一下。

參考資料

[1]TabBar 的 onChange 為什么在同 key 的情況也會(huì)觸發(fā) #5409:https://github.com/ant-design/ant-design-mobile/issues/5409。

[2]這里:https://github.com/ant-design/ant-design-mobile/blob/fae45549bcadb2b3c7f1dea27462543230e3b795/src/utils/use-props-value.ts。

[3]@fenoob://www.zhihu.com/people/05bdf67112572afd5f3526f2eaa425c8。

[4]demo:https://codesandbox.io/s/condescending-pare-1utvlt?file=/src/App.js。

責(zé)任編輯:姜華 來源: 前端桃園
相關(guān)推薦

2021-07-09 08:33:35

React組件受控

2021-03-18 08:00:55

組件Hooks React

2020-10-21 08:38:47

React源碼

2021-09-26 18:43:48

表單受控React

2021-12-13 14:37:37

React組件前端

2019-03-13 10:10:26

React組件前端

2011-07-21 16:10:11

button按鈕jQuery Mobi

2011-07-21 15:50:42

jQuery Mobi頁面對(duì)話框

2021-09-14 18:33:39

React 數(shù)據(jù)交互

2022-09-22 12:38:46

antd form組件代碼

2019-07-22 10:42:11

React組件前端

2011-07-26 08:40:31

jQuery Mobi組件內(nèi)容格式

2011-07-21 16:10:48

jQuery Mobi工具欄

2011-04-02 13:44:08

2021-10-13 14:01:00

函數(shù)React進(jìn)階

2020-11-20 10:52:54

Antd表格日程

2023-10-12 10:10:00

微軟Windows

2017-05-17 15:50:34

開發(fā)前端react

2020-08-26 07:48:41

React Spect組件庫開發(fā)

2017-03-21 21:37:06

組件UI測試架構(gòu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

伊人久久五月天| 亚洲已满18点击进入久久| 国产精品国产三级国产aⅴ浪潮| 少妇人妻好深好紧精品无码| aa亚洲一区一区三区| 一区二区三区免费网站| 久久综合中文色婷婷| 夜夜爽8888| 欧美亚洲三区| 色综合久久悠悠| 免费看黄色的视频| 中文字幕一区二区三区中文字幕| 狠狠色狠狠色综合日日五| 亚洲一区二区三区免费看| 黄色福利在线观看| 久久99热狠狠色一区二区| 91精品国产高清自在线看超| 亚洲欧美精品久久| 婷婷综合一区| 日韩欧美国产一二三区| 午夜免费一区二区| aa国产成人| 亚洲精品国产视频| 日本视频一区二区不卡| 黄色一级大片在线免费看国产一| 久久成人免费电影| 日本午夜精品理论片a级appf发布| 五月婷婷一区二区| 四虎国产精品免费观看| 亚洲男人av电影| 美女黄色一级视频| 国产精品一区二区三区四区在线观看| 色婷婷综合久久久久中文| 99在线观看视频免费| 免费黄色网页在线观看| 国产欧美一区视频| 蜜桃av噜噜一区二区三区| 日本高清视频www| 精品夜夜嗨av一区二区三区| 国产精品视频内| 国产原创popny丨九色| 男人天堂手机在线| 国产日韩欧美综合一区| 精品卡一卡二| 人人妻人人澡人人爽人人欧美一区| 激情综合色综合久久| 国产精品自产拍在线观| 日韩免费av网站| 巨乳诱惑日韩免费av| 97久久精品人搡人人玩| 国产精品第一页在线观看| 国产综合婷婷| 九九热最新视频//这里只有精品 | 日韩伦理在线免费观看| 二区三区在线观看| 国产一区二区三区黄视频| 国产精品日本精品| 成人黄色激情视频| 美洲天堂一区二卡三卡四卡视频| 国产91在线高潮白浆在线观看| 激情五月激情综合| 奇米狠狠一区二区三区| 亚洲区免费影片| 中文字幕 自拍| 欧美hentaied在线观看| 日韩在线精品视频| 美女的奶胸大爽爽大片| 欧美日韩国产探花| 久久久久久国产精品久久| 国产无码精品在线观看| 国产精品亚洲欧美| 国产精品吊钟奶在线| 亚洲图片欧美在线| 国产精品一区二区久激情瑜伽| 亚洲综合精品一区二区| 蜜桃在线一区二区| 久久久不卡影院| 一区二区三区三区在线| 超碰电影在线播放| 午夜精品福利一区二区蜜股av| 黄色网页免费在线观看| 亚洲综合在线电影| 欧美一区二区三级| 噜噜噜在线视频| 欧美理论视频| 欧美裸体xxxx极品少妇| 天堂网一区二区三区| 石原莉奈在线亚洲二区| 96国产粉嫩美女| 台湾av在线二三区观看| 国产精品国产三级国产普通话99 | 日本成人超碰在线观看| 91最新在线免费观看| 视频三区在线观看| 最近日韩中文字幕| 国产精品一区二区免费在线观看| 精品176极品一区| 日韩欧美国产三级| 蜜桃久久精品成人无码av| 伊人情人综合网| 欧洲日本亚洲国产区| 国产熟女一区二区三区四区| 久久久精品免费观看| wwwjizzjizzcom| 黄色亚洲网站| 日韩欧美一级在线播放| 在线视频第一页| 亚洲日本成人| 亚洲综合色av| av在线第一页| 午夜成人在线视频| 91丨porny丨九色| 欧美日韩激情在线一区二区三区| 久久久久久久一区二区三区| 97人妻一区二区精品免费视频 | 亚洲国产精品一区二区第四页av| 国产第一页在线| 欧美区视频在线观看| 久久久久久久久免费看无码 | 欧美性在线视频| www夜片内射视频日韩精品成人| 久久久精品蜜桃| 男人天堂手机在线视频| 韩国一区二区三区视频| 国产亚洲一区二区精品| 国产一级精品视频| 国产sm精品调教视频网站| 伊人久久大香线蕉av一区| 桃子视频成人app| 日韩电影网在线| 1级黄色大片儿| 成人黄色一级视频| 男人c女人视频| 国产精品日韩精品在线播放| 中文字幕在线国产精品| 国产在线一级片| 久久久久久夜精品精品免费| 欧美网站免费观看| 理论片一区二区在线| 精品久久久久久综合日本欧美| 懂色av粉嫩av浪潮av| 天堂久久一区二区三区| 狼狼综合久久久久综合网| 毛片在线网站| 日韩精品亚洲元码| 精品无码人妻一区二区三区| 国产精品18久久久| 国产激情片在线观看| 美国十次综合久久| 九九视频这里只有精品| 亚洲欧美另类视频| 亚洲国产精品综合小说图片区| avtt中文字幕| 伊人久久婷婷| 久久久久九九九| 裤袜国产欧美精品一区| 亚洲人成啪啪网站| av手机天堂网| 国产精品美女久久久久久久久久久| 欧美伦理片在线观看| 四季av一区二区凹凸精品| 成人av在线亚洲| 激情影院在线观看| 日韩欧美一区二区视频| 日韩成人av毛片| 久久久影视传媒| 黄色成人免费看| 正在播放日韩欧美一页| 国产精品免费区二区三区观看| 黄色漫画在线免费看| 亚洲欧美日韩国产精品| 一本一道精品欧美中文字幕| 亚洲欧美电影院| 特级西西人体4444xxxx| 首页国产欧美久久| 99热这里只有精品7| 高潮久久久久久久久久久久久久| 国产91精品久| 黄色片网站在线| 亚洲精品国产综合久久| 中文字幕观看在线| 一区二区三区在线视频观看| 水蜜桃av无码| 久久精品国产亚洲高清剧情介绍 | 性欧美video高清bbw| 亚洲福利精品在线| 最新国产中文字幕| 亚洲一区二区在线视频| 色婷婷av777| 国产酒店精品激情| 国产成人无码一二三区视频| 99精品视频在线观看播放| 国产一区二区免费在线观看| 精品日本视频| 国内精品模特av私拍在线观看 | 欧美精品一区二区免费| 欧美精品少妇| 欧美大片在线观看| 伊人影院中文字幕| 午夜精品一区二区三区电影天堂 | 国产精品色视频| 黄色小说在线播放| 色婷婷久久av| 视频二区在线| 精品卡一卡二卡三卡四在线| 久久国产香蕉视频| 午夜亚洲福利老司机| 亚洲区一区二区三| www激情久久| 少妇极品熟妇人妻无码| 男男视频亚洲欧美| 激情六月丁香婷婷| 欧美性久久久| 中文字幕一区二区三区四区五区六区 | 蜜桃精品成人影片| 国产成人亚洲综合a∨婷婷| 精品日韩久久久| 免费视频一区| 久久99中文字幕| 亚洲老妇激情| 午夜视频久久久| 美女久久99| 国模精品一区二区三区| 亚洲日本va中文字幕| 91免费视频网站| 欧美性www| 国产精品你懂得| 日产精品一区| 日本亚洲欧洲色| 国产福利片在线观看| 色综合五月天导航| www在线观看播放免费视频日本| 一区二区亚洲精品国产| 视频二区在线| 日韩av综合网| 深爱五月激情五月| 亚洲国产97在线精品一区| 亚洲精品久久久狠狠狠爱| 欧美一级xxx| 99久久国产热无码精品免费| 欧美日韩的一区二区| 亚洲熟妇无码久久精品| 欧美艳星brazzers| 中文资源在线播放| 欧洲精品一区二区| www.五月婷婷.com| 欧美在线啊v一区| 国产美女www| 欧美视频在线播放| 亚洲一区精品在线观看| 欧美日韩国产免费一区二区 | 伊人久久av导航| 一级毛片免费高清中文字幕久久网| 国产精品美女在线播放| 在线中文字幕第一区| 日本精品福利视频| 欧美日韩1区| 东北少妇不带套对白| 影音先锋久久| 欧美日韩中文在线视频| 日韩精品欧美精品| 一区二区三区 日韩| 国产主播一区二区三区| 久久久国产精品久久久| 成人国产精品免费观看动漫| 亚洲精品在线视频免费观看| 久久久www成人免费无遮挡大片| 91激情视频在线观看| 自拍偷拍国产亚洲| 国产精品1000| 色综合久久天天综合网| 一区二区视频网| 欧美一区二区视频在线观看2022| 黄色美女一级片| 亚洲视频网站在线观看| 一本一道波多野毛片中文在线| 久热爱精品视频线路一| segui88久久综合9999| 国产精品jvid在线观看蜜臀| 亚洲男人在线| 国产精品yjizz| 精品国产成人| 在线观看17c| 三级在线观看一区二区| 免费国偷自产拍精品视频| eeuss影院一区二区三区| 性猛交ⅹxxx富婆video | 大美女一区二区三区| 熟女人妻在线视频| 国产精品欧美久久久久无广告| 免费人成在线观看| 91福利在线看| 肥臀熟女一区二区三区| 亚洲少妇中文在线| 手机av免费在线| 国产精品美腿一区在线看| 亚洲成人偷拍| 色综合久久av| 一区二区高清| 国产xxxxhd| 国产精品女上位| 狠狠躁夜夜躁人人爽天天高潮| 精品视频在线免费看| 亚洲 小说区 图片区 都市| 久久精品国产久精国产思思| 激情国产在线| 99re6在线| 欧美hd在线| 久久久国产欧美| 97超碰欧美中文字幕| 久久久久久久福利| 欧美日韩日日摸| 久草视频在线看| 国模极品一区二区三区| 91精品亚洲一区在线观看| 日本一区高清不卡| 国产视频久久| 黄色av电影网站| 亚洲欧美日韩国产综合| 中文字幕第99页| 亚洲天堂av高清| 在线观看网站免费入口在线观看国内 | 久在线观看视频| 国产成人午夜片在线观看高清观看| 欧美精品日韩在线| 色综合久久综合中文综合网| 欧美一级在线免费观看| 欧美黄色片免费观看| 日韩专区视频| 一区二区三区我不卡| 日本91福利区| 成人免费视频在线观看| 亚洲免费激情视频| 精品国产乱码久久久久久闺蜜| 国产1区在线| 成人a级免费视频| 日韩精品首页| 国产一伦一伦一伦| 中文字幕精品一区二区三区精品| av毛片在线免费观看| 亚洲区免费影片| 欧美日韩精品免费观看视完整| 欧美福利精品| 美女久久网站| 成熟人妻av无码专区| 在线观看视频一区二区| 国产在线小视频| 国产精品观看在线亚洲人成网| 国产一区二区三区四区五区传媒| 国产成人综合一区| 国产色综合一区| 中文字幕理论片| 色yeye香蕉凹凸一区二区av| 国产成人精品一区二区三区在线 | 成人免费看aa片| 色偷偷成人一区二区三区91| 国产免费av在线| 国产精品日韩欧美综合| 久久美女精品| 日本美女久久久| 亚洲成在线观看| 每日更新在线观看av| 国产精品国产三级国产aⅴ浪潮 | 日韩视频在线观看免费| av日韩一区| 成人一级生活片| 91麻豆精品一区二区三区| 波多野结衣日韩| 久久精品小视频| 另类尿喷潮videofree| 无码日韩人妻精品久久蜜桃| 国产精品免费人成网站| 精品国产乱码久久久久久蜜臀网站| 欧美大片大片在线播放| 日韩理论电影中文字幕| 欧美第一页浮力影院| 亚洲精品久久7777| 青青草免费在线| 国产在线拍揄自揄视频不卡99 | 日韩有码免费视频| 中文字幕亚洲在| 少妇一区二区三区四区| 国产精品嫩草视频| 国内在线观看一区二区三区| 中文字幕狠狠干| 91精品国产手机| 手机在线观看av网站| 亚洲一区二区三区精品视频| 成人午夜免费电影| 一区二区视频免费观看| 国内精品久久久久影院优| jizzjizz欧美69巨大| 一级黄色大片免费看| 在线视频一区二区免费| 天天色天天射天天综合网| 日本在线观看一区二区三区| 国产成人精品aa毛片| 这里只有精品999| 国内伊人久久久久久网站视频| 欧美电影一二区|