|
前段(duan)時間 react hooks 特性刷(shua)得沸沸揚揚的(de),看起(qi)來(lai)挺有意思的(de),估計不(bu)少其他框(kuang)架也(ye)會逐步跟進,所以也(ye)來(lai)嘗試一(yi)下能不(bu)能用在小(xiao)程序上(shang)。 react hooks 允許你在函數式(shi)組件中使(shi)用(yong) state,用(yong)一段官方的簡單例子(zi)概括如下:
函數式組(zu)件(jian)本身非(fei)常簡(jian)潔(jie),不維(wei)護(hu)生命(ming)周期(qi)和狀態,是(shi)一(yi)個可以讓性能得以優化(hua)的(de)使用(yong)方式。但(dan)是(shi)在之前這種方式只能用(yong)于純展(zhan)示組(zu)件(jian)或者(zhe)高階組(zu)件(jian)等,它很難實現一(yi)些交互行為。但(dan)是(shi)在 hooks 出現之后(hou),你就可以為所欲為了(le)。 這里(li)有(you)一份官(guan)方的文檔,不明圍觀(guan)群眾有(you)興趣(qu)的可以點進去了解一下: reactjs.org/docs/hooks-… 。 hooks 的使(shi)用(yong)目(mu)前(qian)有兩個限制:
這個(ge)限(xian)制和 hooks 的實現方式(shi)有(you)(you)關(guan),下面小程序 hooks 也會有(you)(you)同樣(yang)限(xian)制,原因應(ying)該也是類似的。為了能讓開(kai)發者更(geng)好(hao)的使用 hooks,react 官(guan)方也提供了一套 eslint 插件(jian)來協助我們開(kai)發: reactjs.org/docs/hooks-… 。 下面就來介紹下在小程序中的嘗試~ 函數式組件小(xiao)程(cheng)序(xu)沒有(you)(you)提供函數(shu)式組(zu)件(jian),這倒(dao)是(shi)很好理(li)解,小(xiao)程(cheng)序(xu)的(de)(de)架(jia)構是(shi)雙線程(cheng)運行模式,邏輯(ji)層執(zhi)行 js 代碼,視圖層負責(ze)渲染。那么聲明在(zai)(zai)邏輯(ji)層的(de)(de)自定義(yi)組(zu)件(jian)要渲染在(zai)(zai)視圖層必須保(bao)證(zheng)來兩個線程(cheng)都(dou)存在(zai)(zai)自定義(yi)組(zu)件(jian)實(shi)例并一一對(dui)應,這樣的(de)(de)架(jia)構已(yi)經(jing)成(cheng)熟(shu),目前對(dui)函數(shu)式組(zu)件(jian)并沒有(you)(you)強(qiang)烈的(de)(de)需求。在(zai)(zai)基礎庫(ku)不大改的(de)(de)情況下,就算提供了(le)函數(shu)式組(zu)件(jian)也(ye)只(zhi)是(shi)提供了(le)另一種新寫法而(er)已(yi),本(ben)質上的(de)(de)實(shi)現沒有(you)(you)區別也(ye)不能提升什么性能。 不過也(ye)不排除以后小(xiao)程序會提供一種只負(fu)責渲(xuan)染不維(wei)護生命(ming)周期不做(zuo)任何(he)邏(luo)輯的(de)特殊(shu)組件來優化渲(xuan)染性能,這種的(de)話本質上就和函(han)數式(shi)(shi)組件類似了(le),不過函(han)數式(shi)(shi)組件較為(wei)極端的(de)是在(zai)理論(lun)上是有辦法做(zuo)到無實例的(de),這個在(zai)小(xiao)程序中(zhong)怕(pa)是有點困難(nan)。 言歸(gui)正傳,小程(cheng)序(xu)沒有提供(gong)函數式組件(jian),那么就強行封裝出一(yi)個(ge)寫法好了,假(jia)設我(wo)們有一(yi)個(ge)自定義組件(jian),它的 js 和 wxml 內容(rong)分別是這(zhe)樣(yang)的:
一個很奇葩的(de)例(li)子,但是能看明(ming)白就行。小程序里(li)視(shi)圖(tu)和(he)邏(luo)輯分離,不像 react 可以將(jiang)視(shi)圖(tu)和(he)邏(luo)輯寫到(dao)一起,那么小程序里(li)的(de)函數式組件里(li)想(xiang)返回(hui)一串(chuan)渲染邏(luo)輯就不太科學了,這里(li)就改成返回(hui)要用于渲染的(de) state 和(he)方法。 PS:wxml 里不支持 bindtap="setCount(count + 1)" 這種寫法(fa),所以參數(shu)就走(zou) dataset 的(de)方式傳入了。 FunctionComponent 函數其實就相當于封(feng)裝了(le)小程(cheng)序(xu)原有的 Component 構造器,它(ta)的實現類似(si)這樣:
實現很簡(jian)單,就是在 attached 的時候跑一下(xia)傳入的函數,拿到(dao) state 和方法(fa)后(hou)設置到(dao)自定義組件實例上就行。其中(zhong) currentCompInst 和 callIndex 在 useState 和 useEffect 的實現上會用(yong)到(dao),下(xia)面來介紹。 useState 和 useEffect這里的(de)(de)一(yi)個難點(dian)是,useState 是沒有指定變量(liang)名的(de)(de)。初次(ci)渲染還好,二次(ci)渲染的(de)(de)話(hua)要找回這個變量(liang)就(jiu)要費一(yi)段代碼了。 PS:后續的(de)實現除了(le)參(can)考(kao)了(le) react 的(de) hooks 外,也參(can)考(kao)了(le) vue-hooks 的(de)嘗試,有興(xing)趣(qu)的(de)同學(xue)也可以去觀摩一下(xia)。 這里上面提(ti)到的(de) currentCompInst 和 callIndex,將上一次的(de)變(bian)量存儲在(zai) currentCompInst 中,用 callIndex 記錄調用 useState 和 useEffect 的(de)順(shun)序(xu),這樣(yang)就可以在(zai)二(er)次渲(xuan)染(ran)的(de)時(shi)候通過(guo)順(shun)序(xu)找回上一次使用的(de)變(bian)量:
useEffect 的(de)實現邏輯也類似,這(zhe)里就不再貼代碼了。小程(cheng)序本身(shen)沒有提供 render 函(han)數(shu),調 FunctionalComponent 聲明函(han)數(shu)式組件傳入的(de)函(han)數(shu)就作(zuo)為 render 函(han)數(shu)來用。每次調 setXXX 方法——也就是(shi)上面(mian)代碼中返回的(de) updater 的(de)時(shi)候,找到原本存儲這(zhe)個 state 的(de)地方存儲進(jin)去,然后再次執行 render 函(han)數(shu),進(jin)行組件的(de)渲染(ran)。 到這里應(ying)(ying)該就(jiu)明(ming)白了(le),對于 hooks 使(shi)用(yong)為(wei)什么會有一開始的(de)那兩條(tiao)限(xian)制(zhi)。如(ru)果在一些條(tiao)件、循環等語句(ju)內使(shi)用(yong) hooks,就(jiu)無法確保(bao) state 的(de)順序,再二次渲(xuan)染(ran)時就(jiu)不一定能找回(hui)對應(ying)(ying)的(de) state。 |