首頁 web前端 前端問答 小程式能用react嗎

小程式能用react嗎

Dec 29, 2022 am 11:06 AM
小程式

小程式能用react,其使用方法:1、基於「react-reconciler」實作一個渲染器,產生一個DSL;2、建立一個小程式元件,去解析和渲染DSL;3、安裝npm,並執行開發者工具中的建置npm;4、在自己的頁面中引入包,再利用api即可完成開發。

小程式能用react嗎

本教學操作環境:Windows10系統、react18.0.0版、Dell G3電腦。

小程式能用react嗎?

能。

在微信小程式中直接執行React元件

#在研究跨端開發時,我的一個重要目標,是可以讓react元件跑在微信小程式中。在這個過程中,我探索了微信小程式的架構,並引發了許多思考。而作為跨端開發,實際上很難做到write once,run anywhere,因為每個平台所提供的能力是不一樣的,例如微信小程式提供了原生的能力,例如調起相機或其他需要原生環境支援的能力,在微信小程式中開發雖然也是在webview中開展,但是,卻需要一些原生的思維。所以,要做到 write once 就必須有一些限制,這些限制注定了我們無法完全利用小程式的能力,僅僅只用到一些佈局的能力而已。所以,奉勸各位,在做跨端開發時,要有個心理準備。但如果跳出跨端開發,我現在只開發小程序,那我能否用我熟悉的react來開發呢?甚至,能否用我所發展的nautil框架來發展呢?答案是可以的,本文將帶你一步一步實現自己的react小程式開發之路,幫助你在某些特定的場景下,完成​​react專案遷移到小程式的目標。

小程式運行React的方案對比

目前業界能夠比較好支援小程式(沒有特別註明的情況下,小程式特指微信小程式)運行React元件的,有3套方案,分別是京東凹凸實驗室的taro,螞蟻金服某團隊(未找到具體團隊名)的remax,微信某團隊的kbone。

Taro  

  • 編譯,新版本也基於執行時間  

  • 解析為wxml js  

######################################################### #####老牌,不斷發展,全平台支持,持續迭代############Remax ############運行時,帶編譯宏  #### #########基於reconciler ################以recon #################################################################################################################。 #########Kbone ###########在執行階段,依賴webpack ############自己實作一套DOM API ###### #######可相容vue,甚至任意基於DOM渲染的框架 ############效能問題(全量檢查),幾乎停更################################################# ##3套方案各有不同,而且在各自的思路上都是獨樹一格。就我個人而言,如果不考慮跨端開發,自己實作一套DOM API這種方案是非常有價值的,因為DOM介面是HTML標準,你不需要自己去發明一套標準出來,而一旦實現了DOM API,那麼所以其他基於DOM實作的應用理論上都支援在這上面跑。但是,它的不足就是你每換一個平台,就要針對這個平台去實作一套DOM API,這個成本是非常大的,因為DOM介面標準極為龐大,實現的時候也很容易出bug。在我看來,最優雅的實作還是Remax的那種思路,基於react-reconciler做一個渲染器,這個渲染器將react元件實例抽象化為一個統一的DSL,在不同的平台上,去解析渲染這個DSL 。 ######但是remax迭代更新之後,它開始強烈依賴自己的編譯工具,這直接導致我放棄在專案中使用它。因為對於我們自己的專案而言,我們其實有可能不需要它的全部,我們只是使用react來完成我們整個小程式中的某些部分(例如有些已經用react寫好的h5我們想要渲染到小程序,其他部分我們還是在原來的項目中跑)。如果對它的編譯工具有依賴,我們就得把整個專案遷移到它的編譯工具,那我還不如直接使用taro這個老牌比較穩定的工具。 #########整體實作思路#########經過一番研究之後,我決定採用remax的思路,也就是基於react-reconciler實作一個渲染器,產生一個DSL,再建立一個小程式元件,去解析和渲染這個DSL。在完成實作之後,我把所有這些邏輯建構成最終產物,並以npm的形式發布產物,對於小程式開發者而言,只需要npm安裝之後,執行開發者工具中的建置npm即可,之後在自己的頁面中引入這個包,利用api即可完成開發,而不是需要使用另外的編譯工具。 ###

這項方案的最大好處是,對編譯工具的弱(無)依賴,這樣就可以讓我們的這套方案可以在任意的專案中去跑,而不需要額外引入編譯工具切換工具棧。另外,因為reconciler的部分已經打包進npm套件了,所以它是一個可以獨立運行的模組,所以,你甚至可以在mpvue等vue風格或小程式原生風格專案中使用這個npm套件來渲染react的元件。

小程式能用react嗎

微信小程式中運行react元件的想法

#如上圖所示,我們將一個react元件透過基於react-reconciler的渲染器,創建了一個DSL的純物件(包含回呼函數),我們在page的js檔案中,透過this.setData把這個物件傳送給渲染線程,在wxml中使用了我們提供的一個自引用嵌套的元件對DSL進行渲染。這裡需要注意一個點,react-reconciler會在元件更新的時候,觸發對應的鉤子,此時,會再次產生新的DSL,並再次透過this.setData發送渲染。所以,這個渲染器和單純使用createElement的結果是不同的,渲染器支援hooks等react內建的功能。

接下來,我將對其中的具體細節進行講解,以讓你盡可能自己可以手寫出本文所闡述的程式碼,以讓你在自己的專案中可以實現本文一致的效果。你可以克隆這個倉庫到本地,運行效果看看,研究它的整個實現過程。

將react元件渲染為純JS物件

react的渲染器本質上是基於react調度系統的副作用執行器,副作用的結果在web環境下就是DOM的操作,在native環境下就是調用渲染引擎光柵化圖形,在art環境下就是調用聲卡播放聲音,而在我們這次的計劃中,我們需要渲染器生成一個純js對象,以方便交給小程式在小程式的兩個執行緒之間作為訊息體進行傳遞,並基於這個物件在小程式中渲染介面。

有同學對我發出疑問:jsx編譯之後React.createElement的執行結果不就是純JS的物件麼?這裡需要了解react的本質。 react的元件,實際上為react提供了一套描述系統,它描述了react所表達的具體物件的結構。但是,這個描述是抽象的,只有當你把它實例化,運行起來時,它才有意義。我們在元件中所做的描述,可不單單只有jsx的部分,它也包含業務和程序層面的邏輯。例如很多場景下,我們需要根據元件狀態來決定回傳那一部分jsx,以便渲染不同的介面。而這部分內容,需要依賴一個環境來執行,也就是react渲染器。

以前,我們只能模擬react-dom,依照它的運作邏輯,自己手寫一個渲染器。而現在,react把它的調度器專門做了一個函式庫,react-reconciler,幫助開發者快速接入react的調度系統,從而可以建立自己的渲染器。這裡有一個影片(自備梯子),介紹了react-reconciler的基本用法和使用效果。

import Reconciler from 'react-reconciler'
const container = {}
const HostConfig = {
  // ... 极其复杂的一个配置
}
const reconcilerInstance = Reconciler(HostConfig)
let rootContainerInstance = null
export function render(element, { mounted, updated, created }) {
  if (!rootContainerInstance) {
    rootContainerInstance = reconcilerInstance.createContainer(container, false, false)
  }
  return reconcilerInstance.updateContainer(element, rootContainerInstance, null, () => {
    notify = { mounted, updated, created }
    created && created(container)
    mounted(container.data)
  })
}
登入後複製

上面程式碼中,沒有給出的HostConfig的具體內容是關鍵,它用於配製一個Reconciler,從程式碼的角度,它就是一個鉤子函數的集合,我們需要在每個鉤子函數內部寫一些副作用來操作container,你可以看到,在不同的時刻,我們傳入的created, mounted, updated會被調用,而它們接收被操作過的container,從而讓我們獲得這個js對象(container上還有一些函數,但我們可以不用理會,因為this.setData會自動清除這些函數)。

由於這一配置內容太過複雜,要講解清楚需要花費比較大的篇幅,所以我直接把源碼地址貼在這裡,你可以通過閱讀源碼來了解它都有哪些配置項,並且你可以把這部分程式碼拆分出來後,執行一個自己的元件,透過console.log來觀察它們被呼叫的時機以及順序。

總而言之,這些介面都是知識層面的,不是什麼複雜的邏輯,了解每一個配置項目的作用和執行時機之後,你就能寫出自己的渲染器。理論上,它沒有什麼難度。

基於react-reconciler,我在react運行時的每一個環節都做了一些副作用操作,這些副作用的本質,就是修改一個純js對象,當react被運行起來時,它會經歷一個生命週期,這在我的一個影片中有講到react的生命週期的具體過程。你也可以關注我的個人微信公眾號 wwwtangshuangnet 和我討論相關的問題。在每一個生命週期節點上,調度器就會執行一個副作用,也就是修改我提供的那個純js物件。

我提供了兩個方法,用於在小程式的渲染器中,獲得產生好的js物件。得到這個js物件之後,就可以呼叫小程式的this.setData,把這個物件送到渲染執行緒進行渲染。

利用react渲染器得到的纯对象上存在一些函数,调用这些函数会触发它们对应的逻辑(比如调用setState触发hooks状态更新),从而触发调度器中的钩子函数执行,container对象再次被修改,updated被再次调用,this.setData被再次执行,这样,就实现了真正的react运行时在小程序中的植入。

嵌套递归自引用组件

渲染线程接收到this.setData发送过来的js对象后,如何将这个对象作为布局的信息,渲染到界面上呢?由于小程序的特殊架构,它为了安全起见,渲染线程中无法执行可操作界面的脚本,所有的渲染,都得依靠模板语法和少量的wxs脚本。所以,要怎么做呢?

小程序提供了自定义组件的功能,在app.json或对应的page.json中,通过usingComponents来指定一个路径,从而可以在wxml中使用这个组件。而有趣的地方在于,组件本身也可以在组件自己的component.json中使用usingComponents这个配置,而这个配置的内容,可以直接指向自己,例如,我在自己的组件中,这样自引用:

// dynamic.json
{
  "usingComponents": {
    "dynamic": "./dynamic"
  }
}
登入後複製

自己引用自己作为组件之后,在其wxml中,我们就可以使用组件自己去渲染子级数据,即一种嵌套递归的形式进行渲染。

我规定了一种特别的数据结构,大致如下:

{
  type: 'view',
  props: {
    class: 'shadow-component',
    bindtap: (e) => { ... },
  },
  children: [
    {
      type: 'view',
      props: {},
      children: [
        ...
      ],
    },
  ],
}
登入後複製

模板中,通过对type的判断,选择不同的模板代码进行渲染。

<block wx:if="{{ type === &#39;view&#39; }}">
  <view class="{{ props.class }}" bindtap="bindtap">
    <block wx:if="{{ children.length }}" wx:for="{{ children }}">
      <dynamic data="{{ item }}" /> <!-- 嵌套递归 -->
    </block>
  </view>
</block>
登入後複製

在wxml中把所有组件通过这种形式枚举出来之后,这个组件就能按照上述的数据结构递归渲染出整个结构。

当然,这里还需要处理一些细节,例如响应data的变化,事件响应函数等,你可以通过源码了解具体要怎么处理。另外,微信小程序this.setData限制在1M以内,我虽然还没有尝试过很大的数据,但是,这个限制肯定在将来是一个风险点,我现在还没有解决,还在思考应该怎么最小化更新粒度。

不支持直接JSX的变通方法

小程序的编译,没有办法自己配置支持新语法,所以如果我们在小程序代码中使用jsx,就必须先走一遍自己的编译逻辑。有两种解决办法,一种是不使用jsx语法,而是使用hyperscript标记语法,比如:

import { createElement as h } from &#39;react&#39;
function Some() {
  return h(
    &#39;view&#39;,
    { class: &#39;some-component&#39; },
    h(
      &#39;view&#39;,
      { class: &#39;sub-view&#39; },
      &#39;一段文字&#39;,
    ),
    &#39;一段文字&#39;,
  )
}
登入後複製

这样的写法显然没有直接写jsx来的方便,但是阅读上没有什么障碍,且不需要将jsx编译的过程。

另一种办法是走一遍编译,在小程序的页面目录下,创建一个页面同名的.jsx文件,再利用bebel将它编译为.js文件。但是这样的话,你需要在发布小程序的时候,忽略掉所有的.jsx文件。另外,还有一个坑是,小程序的编译不提供process.env,所以编译react的结果用的时候会报错。解决办法是把react的cjs/react.production.min.js作为react的入口文件,通过小程序的构建npm的相关配置逻辑,指定react构建的文件。

结语

本文详细讲解了如何在微信小程序中直接运行react组件的思路,同时,你可以参考这个仓库,运行效果看看,研究它的整个实现过程。总结而言,这个方法分为3个部分:1. 基于react-reconciler实现一个把react组件渲染为纯js对象的渲染器,之所以需要纯js对象,是因为小程序发送到渲染线程的数据必须是纯对象。2. 利用小程序的自定义组件,实现自引用嵌套递归的组件,用于利用上一步得到的js对象渲染成真正的界面。3. 解决jsx问题,将前两步的结果,在page中进行实施,以真正完成在小程序中渲染react组件的效果。当然,本文阐述过程,仅仅提供了这套思路,在真正用到项目中时,使用过程中肯定还会遇到一些坑,仅能作为原有小程序开发项目的补充手段,比如之前写好的react组件不想重新写成小程序版本,那么就可以使用这个方法,同时在渲染组件的地方,把DOM的标签,映射为小程序的标签,就可以在一定程度上解决原有react代码复用的问题。如果你在实操过程中遇到什么问题,欢迎在本文下方留言讨论~

文中链接:
Nautil框架:https://github.com/tangshuang/nautil
演示仓库:https://gitee.com/frustigor/wechat-dynamic-component
Building a Custom React Rendere: https://www.youtube.com/watch?v=CGpMlWVcHok
登入後複製

推荐学习:《react视频教程

以上是小程式能用react嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

使用Python開發微信小程式 使用Python開發微信小程式 Jun 17, 2023 pm 06:34 PM

隨著行動互聯網技術和智慧型手機的普及,微信成為了人們生活中不可或缺的一個應用。而微信小程式則讓人們可以在不需要下載安裝應用程式的情況下,直接使用小程式來解決一些簡單的需求。本文將介紹如何使用Python來開發微信小程式。一、準備工作在使用Python開發微信小程式之前,需要先安裝相關的Python函式庫。這裡推薦使用wxpy和itchat這兩個函式庫。 wxpy是一個微信機器

小程式能用react嗎 小程式能用react嗎 Dec 29, 2022 am 11:06 AM

小程式能用react,其使用方法:1、基於「react-reconciler」實作一個渲染器,產生一個DSL;2、建立一個小程式元件,去解析和渲染DSL;3、安裝npm,並執行開發者工具中的建構npm;4、在自己的頁面中引入包,再利用api即可完成開發。

實作微信小程式中的卡片翻轉特效 實作微信小程式中的卡片翻轉特效 Nov 21, 2023 am 10:55 AM

實作微信小程式中的卡片翻轉特效在微信小程式中,實現卡片翻轉特效是一種常見的動畫效果,可以提升使用者體驗和介面互動的吸引力。以下將具體介紹如何在微信小程式中實現卡片翻轉的特效,並提供相關程式碼範例。首先,需要在小程式的頁面佈局檔案中定義兩個卡片元素,一個用於顯示正面內容,一個用於顯示背面內容,具體範例程式碼如下:&lt;!--index.wxml--&gt;&l

支付寶上線「漢字拾光-生僻字」小程序,用於徵集、補充生僻字庫 支付寶上線「漢字拾光-生僻字」小程序,用於徵集、補充生僻字庫 Oct 31, 2023 pm 09:25 PM

本站10月31日消息,今年5月27日,螞蟻集團宣布啟動“漢字拾光計劃”,最近又迎來新進展:支付寶上線“漢字拾光-生僻字”小程序,用於向社會徵集生僻字,補充生僻字庫,同時提供不同的生僻字輸入體驗,以幫助完善支付寶內的生僻字輸入方法。目前,用戶搜尋「漢字拾光」、「生僻字」等關鍵字就可以進入「生僻字」小程式。在小程式裡,使用者可以提交尚未被系統辨識輸入的生僻字圖片,支付寶工程師確認後,將會對字庫進行補錄入。本站注意到,使用者也可以在小程式體驗最新的拆字輸入法,這項輸入法針對讀音不明確的生僻字設計。用戶拆

uniapp如何實現小程式和H5的快速轉換 uniapp如何實現小程式和H5的快速轉換 Oct 20, 2023 pm 02:12 PM

uniapp如何實現小程式和H5的快速轉換,需要具體程式碼範例近年來,隨著行動網路的發展和智慧型手機的普及,小程式和H5成為了不可或缺的應用形式。而uniapp作為一個跨平台的開發框架,可以在一套程式碼的基礎上,快速實現小程式和H5的轉換,大大提高了開發效率。本文將介紹uniapp如何實現小程式和H5的快速轉換,並給出具體的程式碼範例。一、uniapp簡介unia

用Python編寫簡單的聊天程式教程 用Python編寫簡單的聊天程式教程 May 08, 2023 pm 06:37 PM

實現思路x01服務端的建立首先,在服務端,使用socket進行訊息的接受,每接受一個socket的請求,就開啟一個新的線程來管理訊息的分發與接受,同時,又存在一個handler來管理所有的線程,從而實現對聊天室的各種功能的處理x02客戶端的建立客戶端的建立就要比服務端簡單多了,客戶端的作用只是對消息的發送以及接受,以及按照特定的規則去輸入特定的字符從而實現不同的功能的使用,因此,在客戶端這裡,只需要去使用兩個線程,一個是專門用於接受消息,一個是專門用於發送消息的至於為什麼不用一個呢,那是因為,只

教你如何在小程式中用公眾號範本訊息(附詳細想法) 教你如何在小程式中用公眾號範本訊息(附詳細想法) Nov 04, 2022 pm 04:53 PM

這篇文章給大家帶來了關於微信小程式的相關問題,其中主要介紹瞭如何在小程式中用公眾號範本訊息,下面一起來看一下,希望對大家有幫助。

小程式備案怎麼操作 小程式備案怎麼操作 Sep 13, 2023 pm 04:36 PM

小程序備案操作步驟:1、準備個人身分證影本、企業營業執照影本、法人身分證影本等備案資料;2、登入小程式管理後台;3、進入小程式設定頁;4、選擇“基本設定」;5、填寫備案資料;6、上傳備案資料;7、提交備案申請;8、等待審核結果,如果備案不透過要根據原因進行修改,並重新提交備案申請;9、備案後續操作即可。

See all articles