摘要:下面我們介紹一種全新的處理思路,這種思路在小程序運行期間和真正的幾無區別,不會改變任何代碼語義,表達式只會被處理為方法調用,實際運行的時候就是普通對象,最終通過其他方式渲染出小程序視圖。最終渲染出小程序視圖。
React社區一直在探尋使用React語法開發小程序的方式,其中比較著名的項目有Taro,nanachi。而使用React語法開發小程序的難點主要就是在JSX語法上,JSX本質上是JS,相比于小程序靜態模版來說太靈活。本文所說的新思路就是在處理JSX語法上的新思路,這是一種更加動態的處理思路,相比于現有方案,基本上不會限制任何JSX的寫法,讓你以真正的React方式處理小程序,希望這個新思路可以給任何有志于用React開發小程序的人帶來啟發。
現有思路的局限在介紹新的思路之前,我們先來看下Taro(最新版1.3),nanachi是怎么在小程序端處理JSX語法的。簡單來說,主要是通過在編譯階段把JSX轉化為等效的小程序wxml來把React代碼運行在小程序端的。
舉個例子,比如React邏輯表達式:
xx &&Hello
將會被轉化為等效的小程序wx:if指令:
Hello
這種方式把對JSX的處理,主要放在了編譯階段,他依賴于編譯階段的信息收集,以上面為例,它必須識別出邏輯表達式,然后做對應的wx:if轉換處理。
那編譯階段有什么問題和局限呢?我們以下面的例子說明:
class App extends React.Component { render () { const a =Hello const b = a return ({b} ) } }
首先我們聲明 const a =
這個例子不是特別復雜,卻報錯了。
要想理解上面的代碼為什么報錯,我們首先要理解編譯階段。本質上來說在編譯階段,代碼其實就是‘字符串’,而編譯階段處理方案,就需要從這個‘字符串’中分析出必要的信息(通過AST,正則等方式)然后做對應的等效轉換處理。
而對于上面的例子,需要做什么等效處理呢?需要我們在編譯階段分析出b是JSX片段:b = a =
所以在編譯階段 是無法簡單確定b的值的。
我們再仔細看下上圖的報錯信息:a is not defined。
為什么說a未定義呢?這是涉及到另外一個問題,我們知道
// ReactElement對象 { tag: Text, props: null, children: "Hello" ... }
所以上面那一段代碼在JS環境真正運行的時候,大概等效如下:
class App extends React.Component { render () { const a = { tag: Text, props: null, children: "Hello" ... } const b = a return { tag: View, props: null, children: b ... } } }
但是,我們剛說了編譯階段需要對JSX做等效處理,需要把JSX轉換為wxml,所以
正因為編譯時方案,有如上的限制,在使用的時候常常讓你有“我還是在寫React嗎?”這種感覺。
下面我們介紹一種全新的處理思路,這種思路在小程序運行期間和真正的React幾無區別,不會改變任何代碼語義,JSX表達式只會被處理為React.createElement方法調用,實際運行的時候就是普通js對象,最終通過其他方式渲染出小程序視圖。下面我們仔細說明一下這個思路的具體內容。
第一步:給每個獨立的JSX片段打上唯一標識uuid,假定我們有如下代碼:
const a =Hello const y =
我們給a片段,y片段 添加了uuid屬性
第二步:把React代碼通過babel轉義為小程序可以識別的代碼,例如JSX片段用等效的React.createElement替換等
const a = React.createElement(Text, { uuid: "000001" }, "Hello");
第三步:提取每個獨立的JSX片段,用小程序template包裹,生成wxml文件
Hello
注意這里每一個template 的name標識和 JSX片段的唯一標識uuid是一樣的。最后,需要在結尾生成一個占位模版:。
第四步:修改ReactDOM.render的遞歸(React 16.x之后,不在是遞歸的方式)過程,遞歸執行階段,聚合JSX片段的uuid屬性,生成并返回uiDes數據結構。
第五步:把第四步生成的uiDes,傳遞給小程序環境,小程序把uiDes 設置給占位模版,渲染出最終的視圖。
我們以上面的App組件的例子來說明整個過程,首先js代碼會被轉義為:
class App extends React.Component { render () { const a = React.createElement(Text, {uuid: "000001"}, "Hello"); const b = a return ( React.createElement(View, {uuid: "000002"} , b); ) } }
同時生成wxml文件:
Hello
使用我們定制之后render執行ReactDOM.render(
const uiDes = { name: "000002", child0001: { name: 000001, ... } ... }
小程序獲取到這個uiDes,設置給占位模版。 最終渲染出小程序視圖。
在這整個過程中,你的所有JS代碼都是運行在React過程中的,語義完全一致,JSX片段也不會被任何特殊處理,只是簡單的React.createElement調用,另外由于這里的React過程只是純js運算,執行是非常迅速的,通常只有幾ms。最終會輸出一個uiDes數據到小程序,小程序通過這個uiDes渲染出視圖。
現在我們在看之前的賦值const b = a,就不會有任何問題了,因為a 不過是普通對象。另外對于常見的編譯時方案的限制,比如任意函數返回JSX片段,動態生成JSX片段,for循環使用JSX片段等等,都可以完全解除了,因為JSX片段只是js對象,你可以做任何操作,最終ReactDOM.render會搜集所有執行結果的片段的uuid標識,生成uiDes,而小程序會根據這個uiDes數據結構渲染出最終視圖。
可以看出這種新的思路和以前編譯時方案還是有很大的區別的,對JSX片段的處理是動態的,你可以在任何地方,任何函數出現任何JSX片段, 最終執行結果會確定渲染哪一個片段,只有執行結果的片段的uuid會被寫入uiDes。這和編譯時方案的靜態識別有著本質的區別。
結語"Talk is cheap. Show me your code!" 這僅僅是一個思路?還是已經有落地完整的實現呢?
是有完整的實現的,alita項目在處理JSX語法的時候,采用的就是這個思路,這也是alita基本不限制寫法卻可以轉化整個React Native項目的原因,另外alita在這個思路上做了很多優化。如果對這個思路的具體實現有興趣,可以去研讀一下alita源碼,它完全是開源的https://github.com/areslabs/alita。
當然,你也可以基于這個思路,構造出自己的React小程序開發方案。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104739.html
摘要:是的語法,截止我寫這篇文章為止,小程序還是不支持語法的,所以需要使用這個庫下載,并把文件夾放到目錄下在引入封裝,讓微信的支持語法所有的請求,默認攜帶可以控制是否顯示加載狀態加載中封裝好后就可以在文件中使用了,使用方法如下請 async-await是ES7的語法,截止我寫這篇文章為止,小程序還是不支持async-await語法的,所以需要使用regenerator這個庫 下載regene...
摘要:官方規范估計很難出現現代框架的設計了,因為官方設計中前端三劍客是相互分離的方案,為了解決現階段前端框架的問題,必須由完全接管,這幾乎就是,或者支持語法的,可這與最初網頁設計思路是違背的。現代前端框架正在告訴我們新的三劍客虛擬虛擬。 1 引言 深入思考為何前端需要框架,以及 web components 是否可以代替前端框架? 原文地址,建議先閱讀原文,或者閱讀概述。 2 概述 現在前端...
摘要:也可以安裝瀏覽器插件或,在某個文件的網頁上就能看到一個的按鈕,點擊即可。 【AIS-TXD前端技術月刊】- 本月熱門前端技術快報,匯聚 Github Trending 流行 Repo 和熱門文章,文末有福利 showImg(https://segmentfault.com/img/remote/1460000018406928?w=1352&h=808); 歡迎?訂閱?&?投稿本期小編...
閱讀 2475·2021-11-17 09:33
閱讀 762·2021-11-04 16:13
閱讀 1334·2021-10-14 09:50
閱讀 697·2019-08-30 15:53
閱讀 3663·2019-08-30 14:18
閱讀 3271·2019-08-30 14:14
閱讀 2100·2019-08-30 12:46
閱讀 3185·2019-08-26 14:05