前段時(shí)間 react hooks 特性刷得沸沸揚(yáng)揚(yáng)的,看起來挺有意思的,估計(jì)不少其他框架也會(huì)逐步跟進(jìn),所以也來嘗試一下能不能用在小程序上。 react hooks 允許你在函數(shù)式組件中使用 state,用一段官方的簡單例子概括如下:
函數(shù)式組件本身非常簡潔,不維護(hù)生命周期和狀態(tài),是一個(gè)可以讓性能得以優(yōu)化的使用方式。但是在之前這種方式只能用于純展示組件或者高階組件等,它很難實(shí)現(xiàn)一些交互行為。但是在 hooks 出現(xiàn)之后,你就可以為所欲為了。 這里有一份官方的文檔,不明圍觀群眾有興趣的可以點(diǎn)進(jìn)去了解一下: reactjs.org/docs/hooks-… 。 hooks 的使用目前有兩個(gè)限制:
這個(gè)限制和 hooks 的實(shí)現(xiàn)方式有關(guān),下面小程序 hooks 也會(huì)有同樣限制,原因應(yīng)該也是類似的。為了能讓開發(fā)者更好的使用 hooks,react 官方也提供了一套 eslint 插件來協(xié)助我們開發(fā): reactjs.org/docs/hooks-… 。 下面就來介紹下在小程序中的嘗試~ 函數(shù)式組件小程序沒有提供函數(shù)式組件,這倒是很好理解,小程序的架構(gòu)是雙線程運(yùn)行模式,邏輯層執(zhí)行 js 代碼,視圖層負(fù)責(zé)渲染。那么聲明在邏輯層的自定義組件要渲染在視圖層必須保證來兩個(gè)線程都存在自定義組件實(shí)例并一一對(duì)應(yīng),這樣的架構(gòu)已經(jīng)成熟,目前對(duì)函數(shù)式組件并沒有強(qiáng)烈的需求。在基礎(chǔ)庫不大改的情況下,就算提供了函數(shù)式組件也只是提供了另一種新寫法而已,本質(zhì)上的實(shí)現(xiàn)沒有區(qū)別也不能提升什么性能。 不過也不排除以后小程序會(huì)提供一種只負(fù)責(zé)渲染不維護(hù)生命周期不做任何邏輯的特殊組件來優(yōu)化渲染性能,這種的話本質(zhì)上就和函數(shù)式組件類似了,不過函數(shù)式組件較為極端的是在理論上是有辦法做到無實(shí)例的,這個(gè)在小程序中怕是有點(diǎn)困難。 言歸正傳,小程序沒有提供函數(shù)式組件,那么就強(qiáng)行封裝出一個(gè)寫法好了,假設(shè)我們有一個(gè)自定義組件,它的 js 和 wxml 內(nèi)容分別是這樣的:
一個(gè)很奇葩的例子,但是能看明白就行。小程序里視圖和邏輯分離,不像 react 可以將視圖和邏輯寫到一起,那么小程序里的函數(shù)式組件里想返回一串渲染邏輯就不太科學(xué)了,這里就改成返回要用于渲染的 state 和方法。 PS:wxml 里不支持 bindtap="setCount(count + 1)" 這種寫法,所以參數(shù)就走 dataset 的方式傳入了。 FunctionComponent 函數(shù)其實(shí)就相當(dāng)于封裝了小程序原有的 Component 構(gòu)造器,它的實(shí)現(xiàn)類似這樣:
實(shí)現(xiàn)很簡單,就是在 attached 的時(shí)候跑一下傳入的函數(shù),拿到 state 和方法后設(shè)置到自定義組件實(shí)例上就行。其中 currentCompInst 和 callIndex 在 useState 和 useEffect 的實(shí)現(xiàn)上會(huì)用到,下面來介紹。 useState 和 useEffect這里的一個(gè)難點(diǎn)是,useState 是沒有指定變量名的。初次渲染還好,二次渲染的話要找回這個(gè)變量就要費(fèi)一段代碼了。 PS:后續(xù)的實(shí)現(xiàn)除了參考了 react 的 hooks 外,也參考了 vue-hooks 的嘗試,有興趣的同學(xué)也可以去觀摩一下。 這里上面提到的 currentCompInst 和 callIndex,將上一次的變量存儲(chǔ)在 currentCompInst 中,用 callIndex 記錄調(diào)用 useState 和 useEffect 的順序,這樣就可以在二次渲染的時(shí)候通過順序找回上一次使用的變量:
useEffect 的實(shí)現(xiàn)邏輯也類似,這里就不再貼代碼了。小程序本身沒有提供 render 函數(shù),調(diào) FunctionalComponent 聲明函數(shù)式組件傳入的函數(shù)就作為 render 函數(shù)來用。每次調(diào) setXXX 方法——也就是上面代碼中返回的 updater 的時(shí)候,找到原本存儲(chǔ)這個(gè) state 的地方存儲(chǔ)進(jìn)去,然后再次執(zhí)行 render 函數(shù),進(jìn)行組件的渲染。 到這里應(yīng)該就明白了,對(duì)于 hooks 使用為什么會(huì)有一開始的那兩條限制。如果在一些條件、循環(huán)等語句內(nèi)使用 hooks,就無法確保 state 的順序,再二次渲染時(shí)就不一定能找回對(duì)應(yīng)的 state。 |