Miniprogramm kann React verwenden: 1. Implementieren Sie einen Renderer basierend auf „React-Reconciler“ und generieren Sie eine DSL. 3. Installieren Sie npm und führen Sie Build aus npm in den Entwicklertools. 4. Führen Sie das Paket auf Ihrer eigenen Seite ein und verwenden Sie dann die API, um die Entwicklung abzuschließen.
Die Betriebsumgebung dieses Tutorials: Windows 10-System, Reaktionsversion 18.0.0, Dell G3-Computer.
Können Miniprogramme reagieren?
Ja.
React-Komponenten direkt in WeChat-Miniprogrammen ausführen
Beim Studium der Cross-End-Entwicklung ist es eines meiner wichtigen Ziele, die Ausführung von React-Komponenten in WeChat-Miniprogrammen zu ermöglichen. Während dieses Prozesses habe ich die Architektur von WeChat-Miniprogrammen erkundet und viel Nachdenken angeregt. Bei der Cross-End-Entwicklung ist es tatsächlich schwierig, einmal zu schreiben und überall auszuführen, da die von jeder Plattform bereitgestellten Funktionen unterschiedlich sind. Beispielsweise bietet das WeChat-Applet native Funktionen, z. B. das Einschalten der Kamera oder andere Funktionen, die eine native Funktion erfordern Unterstützende Funktionen: Obwohl die Entwicklung in WeChat-Miniprogrammen auch in der Webansicht erfolgt, ist ein gewisses natives Denken erforderlich. Daher muss es einige Einschränkungen geben, um das einmalige Schreiben zu erreichen. Diese Einschränkungen sollen verhindern, dass wir die Funktionen des Miniprogramms vollständig nutzen und nur einige Layoutfunktionen verwenden. Daher rate ich jedem, bei der terminalübergreifenden Entwicklung mental vorbereitet zu sein. Aber wenn ich mich von der Cross-End-Entwicklung verabschiede und jetzt nur noch kleine Programme entwickle, kann ich dann die Reaktion, mit der ich vertraut bin, für die Entwicklung verwenden? Kann ich überhaupt das Nautil-Framework verwenden, das ich für die Entwicklung entwickelt habe? Die Antwort lautet: Ja, dieser Artikel führt Sie Schritt für Schritt durch die Umsetzung Ihrer eigenen React-Applet-Entwicklung und hilft Ihnen dabei, das Ziel der Migration von React-Projekten auf Applets in bestimmten spezifischen Szenarien zu erreichen.
Vergleich der Lösungen zum Ausführen von React in Miniprogrammen
Derzeit kann die Branche Miniprogramme besser unterstützen (sofern nicht anders angegeben, Miniprogramme beziehen sich speziell auf WeChat-Miniprogramme), um React-Komponenten auszuführen. Es gibt 3 Lösungssätze, nämlich JD .com Taro vom Labor, remax von einem Team bei Ant Financial (es wurde kein spezifischer Teamname gefunden) und kbone von einem Team bei WeChat.
Taro
Kompiliert basiert die neue Version auch auf der Laufzeit
geparst in wxml + js
Alte Marke, kontinuierliche Entwicklung, vollständige Plattformunterstützung, kontinuierliche Iteration
Remax
Laufzeit, mit kompilierten Makros
Basierend auf Reconciler
Das eleganteste, inkrementelle Update
nicht ausgereift genug, nachfolgende Entwicklung ist unbekannt
Kbone
Laufzeit, abhängig vom Webpack
Erzielen Sie es selbst Eine Reihe von DOM-APIs
kompatibel mit Vue und sogar jedem Framework, das auf DOM-Rendering basiert
Leistungsprobleme (vollständige Inspektion), Aktualisierung fast gestoppt
Die drei Lösungssätze sind unterschiedlich und in ihren eigenen Ideen sind alle einzigartig. Wenn Sie persönlich keine Cross-End-Entwicklung in Betracht ziehen, ist es sehr wertvoll, eine Reihe von DOM-APIs selbst zu implementieren, da die DOM-Schnittstelle ein HTML-Standard ist und Sie nicht einmal selbst eine Reihe von Standards erfinden müssen Wenn die DOM-API implementiert ist, können alle anderen auf DOM basierenden Anwendungen theoretisch die Ausführung darauf unterstützen. Der Nachteil besteht jedoch darin, dass bei jedem Plattformwechsel eine Reihe von DOM-APIs für diese Plattform implementiert werden müssen. Dieser Aufwand ist sehr hoch, da der DOM-Schnittstellenstandard extrem umfangreich ist und es bei der Implementierung leicht zu Fehlern kommt . Meiner Meinung nach ist die eleganteste Implementierung die Idee von Remax, einem Renderer, der auf React-Reconciler basiert. Dieser Renderer abstrahiert die React-Komponenteninstanz in eine einheitliche DSL und analysiert und rendert diese DSL auf verschiedenen Plattformen. .
Aber nachdem remax iterativ aktualisiert wurde, begann es sich stark auf seine eigenen Kompilierungstools zu verlassen, was direkt dazu führte, dass ich die Verwendung im Projekt aufgab. Denn für unsere eigenen Projekte benötigen wir möglicherweise nicht alles. Wir verwenden React nur, um bestimmte Teile unseres gesamten kleinen Programms fertigzustellen (z. B. einige in React geschriebene h5-Programme, die wir in das kleine Programm rendern möchten). , wir führen noch andere Teile im Originalprojekt aus). Wenn eine Abhängigkeit von seinem Kompilierungstool besteht, müssen wir das gesamte Projekt auf sein Kompilierungstool migrieren. Dann könnte ich genauso gut Taro verwenden, ein altes und stabiles Tool.
Allgemeine Implementierungsidee
Nach einigen Recherchen habe ich mich für die Remax-Idee entschieden, die darin besteht, einen auf React-Reconciler basierenden Renderer zu implementieren, eine DSL zu generieren und dann eine kleine Programmkomponente zum Parsen und Rendern der DSL zu erstellen . Nach Abschluss der Implementierung habe ich alle diese Logiken in das Endprodukt integriert und das Produkt in Form von npm veröffentlicht. Für kleine Programmentwickler müssen sie nur npm installieren, den Build-npm in den Entwicklertools ausführen und dann dieses Paket einführen in Ihre eigene Seite ein und verwenden Sie die API, um die Entwicklung abzuschließen, ohne dass zusätzliche Kompilierungstools verwendet werden müssen.
Der größte Vorteil dieser Lösung besteht darin, dass sie kaum (keine) Abhängigkeit von Kompilierungstools aufweist, sodass unsere Lösung in jedem Projekt ausgeführt werden kann, ohne dass zusätzliche Kompilierungstools zum Wechseln von Tool-Stacks eingeführt werden müssen. Da der Reconciler-Teil außerdem in das npm-Paket gepackt wurde, handelt es sich um ein Modul, das unabhängig ausgeführt werden kann. Daher können Sie dieses npm-Paket sogar zum Rendern von React-Komponenten in Projekten im Vue-Stil oder im nativen Miniprogramm-Stil verwenden wie mpvue.
Die Idee, React-Komponenten im WeChat-Applet auszuführen
Wie im Bild oben gezeigt, leiten wir eine React-Komponente durch den Renderer basierend auf Reconciler und erstellen ein reines DSL-Objekt (einschließlich Callback-Funktion). . In der js-Datei der Seite wird dieses Objekt über this.setData an den Rendering-Thread gesendet und eine von uns bereitgestellte selbstreferenzielle verschachtelte Komponente wird in wxml zum Rendern des DSL verwendet. Hierbei ist zu beachten, dass Reconciler den entsprechenden Hook auslöst, wenn die Komponente aktualisiert wird. Zu diesem Zeitpunkt wird erneut ein neues DSL generiert und das Rendering erneut über this.setData gesendet. Daher unterscheidet sich das Ergebnis dieses Renderers von dem der einfachen Verwendung von createElement. Der Renderer unterstützt integrierte React-Funktionen wie Hooks.
Als nächstes werde ich die spezifischen Details erläutern, damit Sie den in diesem Artikel beschriebenen Code so weit wie möglich von Hand schreiben können, damit Sie in Ihrem eigenen Projekt den gleichen Effekt wie in diesem Artikel erzielen können. Sie können dieses Warehouse lokal klonen, den laufenden Effekt sehen und den gesamten Implementierungsprozess studieren.
Rendern Sie Reaktionskomponenten in reine JS-Objekte
Der React-Renderer ist im Wesentlichen ein Nebeneffekt-Executor, der auf dem React-Scheduling-System basiert. Das Ergebnis des Nebeneffekts ist der DOM-Vorgang in der Webumgebung, der in der Webumgebung als Rendering bezeichnet wird Native Umgebung. In der Kunstumgebung ruft sie die Soundkarte auf, um den Sound abzuspielen. Diesmal benötigen wir den Renderer, um ein reines JS-Objekt zu generieren, damit es an das Applet übergeben werden kann eine Funktion zwischen den beiden Threads des Applets. Der Nachrichtentext wird übergeben und die Schnittstelle wird im Applet basierend auf diesem Objekt gerendert.
Einige Studenten fragten mich: Ist das Ausführungsergebnis von React.createElement nach der jsx-Kompilierung nicht ein reines JS-Objekt? Hier müssen Sie die Essenz der Reaktion verstehen. Die Komponenten von React stellen tatsächlich ein Beschreibungssystem für React bereit, das die Struktur der spezifischen Objekte beschreibt, die durch React ausgedrückt werden. Diese Beschreibung ist jedoch abstrakt und ergibt nur dann Sinn, wenn Sie sie instanziieren und ausführen. Die Beschreibung, die wir in der Komponente vornehmen, ist nicht nur der JSX-Teil, sondern umfasst auch Logik auf Geschäfts- und Programmebene. In vielen Szenarien müssen wir beispielsweise basierend auf dem Komponentenstatus entscheiden, welcher Teil von jsx zurückgegeben werden soll, um verschiedene Schnittstellen zu rendern. Dieser Teil des Inhalts muss für die Ausführung auf eine Umgebung angewiesen sein, bei der es sich um den React-Renderer handelt.
In der Vergangenheit konnten wir React-Dom nur simulieren und einen Renderer entsprechend seiner Betriebslogik selbst schreiben. Jetzt hat React eine Bibliothek speziell für seinen Scheduler React-Reconciler erstellt, um Entwicklern einen schnellen Zugriff auf das Planungssystem von React zu ermöglichen, damit sie ihre eigenen Renderer erstellen können. Hier ist ein Video (bringen Sie Ihre eigene Leiter mit), das die grundlegende Verwendung und die Auswirkungen von React-Reconciler vorstellt.
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) }) }
Im obigen Code ist der spezifische Inhalt von HostConfig der Schlüssel. Er wird zur Vorbereitung eines Reconcilers verwendet. Aus Code-Sicht handelt es sich um eine Sammlung von Hook-Funktionen Wenn Sie den Container bedienen, können Sie sehen, dass die von uns übergebenen erstellten, gemounteten und aktualisierten Funktionen zu unterschiedlichen Zeiten aufgerufen werden und den betriebenen Container empfangen, sodass wir das js-Objekt erhalten können (es gibt auch einige). Funktionen auf dem Container, aber wir können es ignorieren, da this.setData diese Funktionen automatisch löscht).
Da dieser Konfigurationsinhalt zu kompliziert ist, würde es viel Platz in Anspruch nehmen, ihn klar zu erklären. Deshalb füge ich die Quellcodeadresse direkt hier ein. Sie können verstehen, welche Konfigurationselemente er enthält, indem Sie den Quellcode lesen und eingeben Nachdem Sie einen Teil des Codes aufgeteilt haben, führen Sie eine eigene Komponente aus und verwenden Sie console.log, um den Zeitpunkt und die Reihenfolge ihres Aufrufs zu beobachten.
Alles in allem handelt es sich bei diesen Schnittstellen um eine Wissensebene und nicht um eine komplizierte Logik. Nachdem Sie die Rolle und den Ausführungszeitpunkt jedes Konfigurationselements verstanden haben, können Sie Ihren eigenen Renderer schreiben. Theoretisch ist es nicht so schwierig.
Basierend auf React-Reconciler habe ich in jedem Aspekt der React-Laufzeit einige Nebeneffekte durchgeführt. Der Kern dieser Nebeneffekte besteht darin, ein reines JS-Objekt zu ändern, wenn es ausgeführt wird. In einem meiner Videos habe ich über den spezifischen Prozess des Reaktionslebenszyklus gesprochen. Sie können auch meinem persönlichen öffentlichen WeChat-Konto wwwtangshuangnet folgen und verwandte Themen mit mir besprechen. Auf jedem Lebenszyklusknoten führt der Scheduler einen Nebeneffekt aus, nämlich das von mir bereitgestellte reine JS-Objekt zu ändern.
Ich stelle zwei Methoden bereit, um das generierte JS-Objekt im Renderer des Miniprogramms abzurufen. Nachdem Sie dieses js-Objekt erhalten haben, können Sie this.setData des Applets aufrufen und dieses Objekt zum Rendern an den Rendering-Thread senden.
利用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 === 'view' }}"> <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 'react' function Some() { return h( 'view', { class: 'some-component' }, h( 'view', { class: 'sub-view' }, '一段文字', ), '一段文字', ) }
这样的写法显然没有直接写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视频教程》
Das obige ist der detaillierte Inhalt vonKönnen kleine Programme reagieren?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!