


How to build applets in React? Two implementation solutions shared
Dec 23, 2021 am 10:27 AMHow to build small programs in React? The following article will reveal how React runs on the mini program platform through 1,500 lines of code, and introduce two implementation options for building mini programs with React. I hope it will be helpful to you!
Have you ever used similar frameworks like Taro and Remax? Do you want to know how this kind of framework implements React code to run on the mini program platform? If so, then maybe you can spend a cup of coffee and continue reading. This article will use two solutions to implement React to run on the mini program platform. If you want to read these 1,500 lines of implementation code now, you can directly click on Project Source Code to get it (maybe you have to drink a few more cups of coffee).
Project Description
In order to describe the implementation process more clearly, we treat the implementation plan as a project.
Project requirements: Make the React code with the following counter function run on the WeChat mini program platform.
import React, { Component } from 'react' import { View, Text, Button } from '@leo/components' import './index.css' export default class Index extends Component { constructor() { super() this.state = { count: 0 } this.onAddClick = this.onAddClick.bind(this) this.onReduceClick = this.onReduceClick.bind(this) } componentDidMount () { console.log('執(zhí)行componentDidMount') this.setState({ count: 1 }) } onAddClick() { this.setState({ count: this.state.count + 1 }) } onReduceClick() { this.setState({ count: this.state.count - 1 }) } render () { const text = this.state.count % 2 === 0 ? '偶數(shù)' : '奇數(shù)' return ( <View className="container"> <View className="conut"> <Text>count: {this.state.count}</Text> </View> <View> <Text className="text">{text}</Text> </View> <Button onClick={this.onAddClick} className="btn">+1</Button> <Button onClick={this.onReduceClick} className="btn">-1</Button> </View> ) } }
If you have used frameworks such as Taro or Remax, you should feel familiar with the above code. The above code officially imitates the React DSL writing method of such frameworks. If you want to urgently see the effect of realizing this requirement, you can click on this Project Source Code to obtain the source code, and then run the project according to the prompts, and you can observe the following effect:
At this point, we have a clear understanding of the needs of this project and what the final results will be. Next, we will focus on the specific implementation of the process from the demand point to the results.
Implementation plan
Building mini program framework products
Students who have developed mini programs know that the mini program framework includes the main body and the page, where the main body is generated by three files It consists of and must be placed in the root directory. These three files are: app.js
(required, mini program logic), app.json
(required, mini program public configuration) ), app.wxss
(optional, mini program public style sheet). So to build React code into mini program code, you first need to generate app.js
and app.json
files. Because this conversion does not involve the app.js
file, the app.js
content can be written directly to App({})
instead. app.json
is a configuration file. You can directly add a app.config.js
to the React project to fill in the configuration content. That is, the React code project directory is as follows:
├── src │ ├── app.config.js // 小程序配置文件,用來生成app.json內(nèi)容 │ └── pages │ └── index │ ├── index.css │ └── index.jsx // React代碼,即上述計數(shù)器代碼 └── tsconfig.json
app.config.js
The content is the global configuration content of the mini program, as follows:
module.exports = { pages: ['pages/index/index'], window: { navigationBarTitleText: 'react-wxapp', navigationBarBackgroundColor: '#282c34' } };
With this configuration file, you can generate app.js# in the following way ## and
app.json files.
/*outputDir為小程序代碼生成目錄*/ fs.writeFileSync(path.join(outputDir, './app.js'), `App({})`) fs.writeFileSync(path.join(outputDir, './app.json'), JSON.stringify(config, undefined, 2)) // config即為app.config.js文件內(nèi)容The mini program page is composed of four types of files, namely
js (required, page logic),
wxml (required, page structure) ,
json (optional, page configuration),
wxss (optional, page style sheet). When converting React code into a small program, the main consideration is how to convert the
js and
wxml type files corresponding to the React code conversion program, which will be explained in detail later.
project source code of this project, you can find that these two methods are also reflected in the source code (compile-time implementation directory: packages/compile-core; run-time implementation directory :
packages/runtime-core).
react-reconciler, so that the React code can actually run into the mini program, similar to Taro3.0, Remax, etc., so this method has no syntax restrictions, but performance will be poor. This
project source code is implemented with reference to the source code of frameworks such as Taro and Remax and simplifies many details. Therefore, this project source code is only suitable for learning and cannot be put into actual business use. .
接下來將分別講述如何通過編譯時和運(yùn)行時這兩種方式來實(shí)現(xiàn) React 運(yùn)行到小程序平臺。
編譯時實(shí)現(xiàn)
在講述具體實(shí)現(xiàn)流程之前,首先需要了解下編譯時實(shí)現(xiàn)這個名詞的概念,首先這里的編譯并非傳統(tǒng)的高大上“編譯”,傳統(tǒng)意義上的編譯一般將高級語言往低級語言進(jìn)行編譯,但這里只是將同等水平語言轉(zhuǎn)換,即將javascript
代碼字符串編譯成另一種javascript
代碼字符串,因此這里的編譯更類似于“轉(zhuǎn)譯”。其次,雖然這里稱編譯時實(shí)現(xiàn),并非所有實(shí)現(xiàn)過程都是編譯的,還是需要少部分實(shí)現(xiàn)需要運(yùn)行時配合,因此這種方式稱為重編譯輕運(yùn)行方式更為合適。同樣的,運(yùn)行時實(shí)現(xiàn)也含有少量編譯時實(shí)現(xiàn),亦可稱為重運(yùn)行輕編譯方式。
為了方便實(shí)現(xiàn)將javascript
代碼字符串編譯成另一種javascript
代碼字符串,這里直接采用Babel
工具,由于篇幅問題,這里就不詳細(xì)講述Babel
用法了,如果對Babel
不熟的話,可以看看這篇文章簡單了解下(沒錯,就是給自己打廣告)。接下來我們來分析編譯時實(shí)現(xiàn)步驟有哪些:
1. JSX轉(zhuǎn)換成對應(yīng)小程序的模板
React是通過JSX
來渲染視圖的,而小程序則通過wxml
來渲染視圖,要將 React 運(yùn)行到小程序上,其重點(diǎn)就是要如何實(shí)現(xiàn)JSX
轉(zhuǎn)換成對應(yīng)的小程序的wxml
,其轉(zhuǎn)換規(guī)則就是將JSX
使用語法轉(zhuǎn)換成小程序相同功能的語法,例如:
標(biāo)簽元素轉(zhuǎn)換:
View
、Text
、Button
等標(biāo)簽直接映射為小程序基礎(chǔ)組件本身(改為小寫)樣式類名轉(zhuǎn)換:
className
修改為class
<View className="xxx" /> ==> <View class="xxx" />
事件轉(zhuǎn)換:如
onClick
修改為bindtap
<View onClick=xxx /> ==> <View bindtap =xxx />
循環(huán)轉(zhuǎn)換:
map
語法修改為wx:for
list.map(i => <Text>{i}</Text>) => <Text wx:for="{{list}}">{{item}}</Text>
語法轉(zhuǎn)換遠(yuǎn)不止上面這些類型,如果要保證開發(fā)者可以使用各種JSX
語法開發(fā)小程序,就需要盡可能窮舉出所有語法轉(zhuǎn)換規(guī)則,否則很可能開發(fā)者用了一個寫法就不支持轉(zhuǎn)換。而事實(shí)是,有些寫法(比如動態(tài)生成JSX片段等等)是根本無法支持轉(zhuǎn)換,這也是前文為什么說編譯時實(shí)現(xiàn)方案的缺點(diǎn)是語法有限制,開發(fā)者不能隨意編碼,需要受限于框架本身開發(fā)規(guī)則。
由于上述需要轉(zhuǎn)換JSX
代碼語法相對簡單,只需要涉及幾種簡單語法規(guī)則轉(zhuǎn)換,這里直接貼出轉(zhuǎn)換后的wxml
結(jié)果如下,對應(yīng)的實(shí)現(xiàn)代碼位于:packages/compile-core/transform/parseTemplate.ts
。
<view class="container"> <view class="conut"><Text>count: {{count}}</Text></view> <view> <text class="text">{{text}}</text> </view> <button bindtap="onAddClick" class="btn">+1</button> <button bindtap="onReduceClick" class="btn">-1</button> </view>
2. 運(yùn)行時適配
如前文所說,雖然這個方案稱為編譯時實(shí)現(xiàn),但是要將React
代碼在小程序平臺驅(qū)動運(yùn)行起來,還需要在運(yùn)行時做下適配處理。適配處理主要在小程序js
邏輯實(shí)現(xiàn),內(nèi)容主要有三塊:數(shù)據(jù)渲染、事件處理、生命周期映射。
小程序js
邏輯是通過一個object
參數(shù)配置聲明周期、事件等來進(jìn)行注冊,并通過setData
方法觸發(fā)視圖渲染:
Component({ data: {}, onReady () { this.setData(..) }, handleClick () {} })
而計數(shù)器React
代碼是通過class
聲明一個組件邏輯,類似:
class CustomComponent extends Component { state = { } componentDidMount() { this.setState(..) } handleClick () { } }
從上面兩段代碼可以看出,小程序是通過object
聲明邏輯,React 則是通過class
進(jìn)行聲明。除此之外,小程序是通過setData
觸發(fā)視圖(wxml
)渲染,React 則是通過 setState
觸發(fā)視圖(render
方法)渲染。所以要使得 React 邏輯可以運(yùn)行到小程序平臺,可以加入一個運(yùn)行時墊片,將兩者邏輯寫法通過墊片對應(yīng)起來。再介紹運(yùn)行時墊片具體實(shí)現(xiàn)前,還需要對上述 React 計數(shù)器代碼進(jìn)行簡單的轉(zhuǎn)換處理,處理完的代碼如下:
import React, { Component } from "../../npm/app.js"; // 1.app.js為墊片實(shí)現(xiàn)文件 export default class Index extends Component { static $$events = ["onAddClick", "onReduceClick"]; // 2.收集JSX事件名稱 constructor() { super(); this.state = { count: 0 }; this.onAddClick = this.onAddClick.bind(this); this.onReduceClick = this.onReduceClick.bind(this); } componentDidMount() { console.log('執(zhí)行componentDidMount'); this.setState({ count: 1 }); } onAddClick() { this.setState({ count: this.state.count + 1 }); } onReduceClick() { this.setState({ count: this.state.count - 1 }); } createData() { // 3.render函數(shù)改為createData,刪除 this.__state = arguments[0]; // 原本的JSX代碼,返回更新后的state // 提供給小程序進(jìn)行setData const text = this.state.count % 2 === 0 ? '偶數(shù)' : '奇數(shù)'; Object.assign(this.__state, { text: text }); return this.__state; } } Page(require('../../npm/app.js').createPage(Index))。 // 4.使用運(yùn)行時墊片提供的createPage // 方法進(jìn)行初始化 // 方法進(jìn)行初始化復(fù)制代碼
如上代碼,需要處理的地方有4處:
Component
進(jìn)行重寫,重寫邏輯在運(yùn)行時墊片文件內(nèi)實(shí)現(xiàn),即app.js
,實(shí)現(xiàn)具體邏輯后文會貼出。將原本
JSX
的點(diǎn)擊事件對應(yīng)的回調(diào)方法名稱進(jìn)行收集,以便在運(yùn)行時墊片在小程序平臺進(jìn)行事件注冊。因?yàn)樵?code>render方法內(nèi)
JSX
片段轉(zhuǎn)換為wxml
了,所以這里render
方法可將JSX
片段進(jìn)行刪除。另外因?yàn)?code>React每次執(zhí)行setState
都會觸發(fā)render
方法,而render
方法內(nèi)會接受到最新的state
數(shù)據(jù)來更新視圖,因此這里產(chǎn)生的最新state
正是需要提供給小程序的setData
方法,從而觸發(fā)小程序的數(shù)據(jù)渲染,為此將render
名稱重命名為createData
(生產(chǎn)小程序的data
數(shù)據(jù)),同時改寫內(nèi)部邏輯,將產(chǎn)生的最新state
進(jìn)行返回。使用運(yùn)行時墊片提供的
createPage
方法進(jìn)行初始化(createPage
方法實(shí)現(xiàn)具體邏輯后文會貼出),同時通過小程序平臺提供的Page
方法進(jìn)行注冊,從這里可得知createPage
方法返回的數(shù)據(jù)肯定是一個object
類型。
運(yùn)行時墊片(app.js)實(shí)現(xiàn)邏輯如下:
export class Component { // 重寫Component的實(shí)現(xiàn)邏輯 constructor() { this.state = {} } setState(state) { // setState最終觸發(fā)小程序的setData update(this.$scope.$component, state) } _init(scope) { this.$scope = scope } } function update($component, state = {}) { $component.state = Object.assign($component.state, state) let data = $component.createData(state) // 執(zhí)行createData獲取最新的state data['$leoCompReady'] = true $component.state = data $component.$scope.setData(data) // 將state傳遞給setData進(jìn)行更新 } export function createPage(ComponentClass) { // createPage實(shí)現(xiàn)邏輯 const componentInstance = new ComponentClass() // 實(shí)例化傳入進(jìn)來React的Class組件 const initData = componentInstance.state const option = { // 聲明一個小程序邏輯的對象字面量 data: initData, onLoad() { this.$component = new ComponentClass() this.$component._init(this) update(this.$component, this.$component.state) }, onReady() { if (typeof this.$component.componentDidMount === 'function') { this.$component.componentDidMount() // 生命邏輯映射 } } } const events = ComponentClass['$$events'] // 獲取React組件內(nèi)所有事件回調(diào)方法名稱 if (events) { events.forEach(eventHandlerName => { if (option[eventHandlerName]) return option[eventHandlerName] = function () { this.$component[eventHandlerName].call(this.$component) } }) } return option }
上文提到了重寫Component
類和createPage
方法具體實(shí)現(xiàn)邏輯如上代碼所示。
Component
內(nèi)聲明的state
會執(zhí)行一個update
方法,update
方法里主要是將 React 產(chǎn)生的新state
和舊state
進(jìn)行合并,然后通過上文說的createData
方法獲取到合并后的最新state
,最新的state
再傳遞給小程序進(jìn)行setData
,從而實(shí)現(xiàn)小程序數(shù)據(jù)渲染。
createPage
方法邏輯首先是將 React 組件實(shí)例化,然后構(gòu)建出一個小程序邏輯的對應(yīng)字面量,并將 React 組件實(shí)例相關(guān)方法和這個小程序邏輯對象字面量進(jìn)行綁定:其次進(jìn)行生命周期綁定:在小程序onReady
周期里出發(fā) React 組件對應(yīng)的componentDidMount
生命周期;最好進(jìn)行事件綁定:通過上文提到的回調(diào)事件名,取出React 組件實(shí)例內(nèi)的對應(yīng)的事件,并將這些事件注冊到小程序邏輯的對應(yīng)字面量內(nèi),這樣就完成小程序平臺事件綁定。最后將這個對象字面量返回,供前文所說的Page
方法進(jìn)行注冊。
到此,就可以實(shí)現(xiàn) React 代碼運(yùn)行到小程序平臺了,可以在項(xiàng)目源碼里執(zhí)行 npm run build:compile
看看效果。編譯時實(shí)現(xiàn)方案主要是通過靜態(tài)編譯JSX
代碼和運(yùn)行時墊片結(jié)合,完成 React 代碼運(yùn)行到小程序平臺,這種方案基本無性能上的損耗,且可以在運(yùn)行時墊片做一些優(yōu)化處理(比如去除不必要的渲染數(shù)據(jù),減少setData數(shù)據(jù)量),因此其性能與使用小程序原生語法開發(fā)相近甚至某些場景會更優(yōu)。然而這種方案的缺點(diǎn)就是語法限制問題(上文已經(jīng)提過了),使得開發(fā)并不友好,因此也就有了運(yùn)行時實(shí)現(xiàn)方案的誕生。
運(yùn)行時實(shí)現(xiàn)
從上文可以看出,編譯時實(shí)現(xiàn)之所以有語法限制,主要因?yàn)槠洳皇亲?React 真正運(yùn)行到小程序平臺,而運(yùn)行時實(shí)現(xiàn)方案則可以,其原理是在小程序平臺實(shí)現(xiàn)一個 React 自定義渲染器,用來渲染 React 代碼。這里我們以 remax 框架實(shí)現(xiàn)方式來進(jìn)行講解,本項(xiàng)目源碼中的運(yùn)行時實(shí)現(xiàn)也正是參照 remax 框架實(shí)現(xiàn)的。
如果使用過 React 開發(fā)過 Web,入口文件有一段類似這樣的代碼:
import React from 'react' import ReactDom from 'react-dom' import App from './App' ReactDom.render( App, document.getElementById('root') )
可以看出渲染 Web 頁面需要引用一個叫 react-dom
模塊,那這個模塊作用是什么?react-dom
是 Web 平臺的渲染器,主要負(fù)責(zé)將 React 執(zhí)行后的Vitrual DOM
數(shù)據(jù)渲染到 Web 平臺。同樣的,React 要渲染到 Native,也有一個針對 Native 平臺的渲染器:React Native
。
React實(shí)現(xiàn)多平臺方式,是在每個平臺實(shí)現(xiàn)一個React渲染器,如下圖所示。
而如果要將 React 運(yùn)行到小程序平臺,只需要開發(fā)一個小程序自定義渲染器即可。React 官方提供了一個react-reconciler 包專門來實(shí)現(xiàn)自定義渲染器,官方提供了一個簡單demo重寫了react-dom
。
使用react-reconciler
實(shí)現(xiàn)渲染器主要有兩步,第一步:實(shí)現(xiàn)渲染函數(shù)(render
方法),類似ReactDOM.render
方法:
import ReactReconciler from 'react-reconciler' import hostConfig from './hostConfig' // 宿主配置 // 創(chuàng)建Reconciler實(shí)例, 并將HostConfig傳遞給Reconciler const ReactReconcilerInst = ReactReconciler(hostConfig) /** * 提供一個render方法,類似ReactDom.render方法 * 與ReactDOM一樣,接收三個參數(shù) * render(<MyComponent />, container, () => console.log('rendered')) */ export function render(element, container, callback) { // 創(chuàng)建根容器 if (!container._rootContainer) { container._rootContainer = ReactReconcilerInst.createContainer(container, false); } // 更新根容器 return ReactReconcilerInst.updateContainer(element, container._rootContainer, null, callback); }
第二步,如上圖引用的import hostConfig from './hostConfig'
,需要通過react-reconciler
實(shí)現(xiàn)宿主配置(HostConfig
),HostConfig
是宿主環(huán)境提供一系列適配器方案和配置項(xiàng),定義了如何創(chuàng)建節(jié)點(diǎn)實(shí)例、構(gòu)建節(jié)點(diǎn)樹、提交和更新等操作,完整列表可以點(diǎn)擊查看。值得注意的是在小程序平臺未提供DOM API
操作,只能通過setData
將數(shù)據(jù)傳遞給視圖層。因此Remax
重新定義了一個VNode
類型的節(jié)點(diǎn),讓 React 在reconciliation
過程中不是直接去改變DOM
,而先更新VNode
,hostConfig
文件內(nèi)容大致如下:
interface VNode { id: number; // 節(jié)點(diǎn) id,這是一個自增的唯一 id,用于標(biāo)識節(jié)點(diǎn)。 container: Container; // 類似 ReactDOM.render(<App />, document.getElementById('root') 中的第二個參數(shù) children: VNode[]; // 子節(jié)點(diǎn)。 type: string | symbol; // 節(jié)點(diǎn)的類型,也就是小程序中的基礎(chǔ)組件,如:view、text等等。 props?: any; // 節(jié)點(diǎn)的屬性。 parent: VNode | null; // 父節(jié)點(diǎn) text?: string; // 文本節(jié)點(diǎn)上的文字 appendChild(node: VNode): void; removeChild(node: VNode): void; insertBefore(newNode: VNode, referenceNode: VNode): void; ... } // 實(shí)現(xiàn)宿主配置 const hostConfig = { ... // reconciler提交后執(zhí)行,觸發(fā)容器更新數(shù)據(jù)(實(shí)際會觸發(fā)小程序的setData) resetAfterCommit: (container) => { container.applyUpdate(); }, // 創(chuàng)建宿主組件實(shí)例,初始化VNode節(jié)點(diǎn) createInstance(type, newProps, container) { const id = generate(); const node = new VNode({ ... }); return node; }, // 插入節(jié)點(diǎn) appendChild(parent, child) { parent.appendChild(child); }, // insertBefore(parent, child, beforeChild) { parent.insertBefore(child, beforeChild); }, // 移除節(jié)點(diǎn) removeChild(parent, child) { parent.removeChild(child); } ... };
除了上面的配置內(nèi)容,還需要提供一個容器用來將VNode
數(shù)據(jù)格式化為JSON
數(shù)據(jù),供小程序setData
傳遞給視圖層,這個容器類實(shí)現(xiàn)如下:
class Container { constructor(context) { this.root = new VNode({..}); // 根節(jié)點(diǎn) } toJson(nodes ,data) { // 將VNode數(shù)據(jù)格式化JSON const json = data || [] nodes.forEach(node => { const nodeData = { type: node.type, props: node.props || {}, text: node.text, id: node.id, children: [] } if (node.children) { this.toJson(node.children, nodeData.children) } json.push(nodeData) }) return json } applyUpdate() { // 供HostConfig配置的resetAfterCommit方法執(zhí)行 const root = this.toJson([this.root])[0] console.log(root) this.context.setData({ root}); } ... }
緊接著,我們封裝一個createPageConfig
方法,用來執(zhí)行渲染,其中Page
參數(shù)為 React 組件,即上文計數(shù)器的組件。
import * as React from 'react'; import Container from './container'; // 上文定義的Container import render from './render'; // 上文定義的render方法 export default function createPageConfig(component) { // component為React組件 const config = { // 小程序邏輯對象字面量,供Page方法注冊 data: { root: { children: [], } }, onLoad() { this.container = new Container(this, 'root'); const pageElement = React.createElement(component, { page: this, }); this.element = render(pageElement, this.container); } }; return config; }
到這里,基本已經(jīng)實(shí)現(xiàn)完小程序渲染器了,為了使代碼跑起來,還需要通過靜態(tài)編譯改造下 React 計數(shù)器組件,其實(shí)就是在末尾插入一句代碼:
import React, { Component } from 'react'; export default class Index extends Component { constructor() { super(); this.state = { count: 0 }; this.onAddClick = this.onAddClick.bind(this); this.onReduceClick = this.onReduceClick.bind(this); } ... } // app.js封裝了上述createPage方法 Page(require('../../npm/app.js').createPage(Index))
通過這樣,就可以使得React代碼在小程序真正運(yùn)行起來了,但是這里我們還有個流程沒介紹,上述Container
類的applyUpdate
方法中生成的頁面JSON
數(shù)據(jù)要如何更新到視圖?首先我們先來看下這個JSON
數(shù)據(jù)長什么樣子:
// 篇幅問題,這里只貼部分?jǐn)?shù)據(jù) { "type": "root", "props": {}, "id": 0, "children": [{ "type": "view", "props": { "class": "container" }, "id": 12, "children": [{ "type": "view", "props": { "class": "conut" }, "id": 4, "children": [{ "type": "text", "props": {}, "id": 3, "children": [{ "type": "plain-text", "props": {}, "text": "count: ", "id": 1, "children": [] }, { "type": "plain-text", "props": {}, "text": "1", "id": 2, "children": [] }] }] } ... ... }] }
可以看出JSON
數(shù)據(jù),其實(shí)是一棵類似Tree UI
的數(shù)據(jù),要將這些數(shù)據(jù)渲染出頁面,可以使用小程序提供的Temlate
進(jìn)行渲染,由于小程序模板遞歸嵌套會有問題(微信小程序平臺限制),因此需要提供多個同樣組件類型的模板進(jìn)行遞歸渲染,代碼如下:
<template is="TPL" data="{{root: root}}" /> <!-- root為上述的JSON數(shù)據(jù) --> <template name="TPL"> <block wx:for="{{root.children}}" wx:key="id"> <template is="TPL_1_CONTAINER" data="{{i: item, a: ''}}" /> </block> </template> <template name="TPL_1_view"> <view style="{{i.props.style}}" class="{{i.props.class}}" bindtap="{{i.props.bindtap}}" > <block wx:for="{{i.children}}" wx:key="id"> <template is="{{'TPL_' + (tid + 1) + '_CONTAINER'}}" data="{{i: item, a: a, tid: tid + 1 }}" /> </block> </view> </template> <template name="TPL_2_view"> <view style="{{i.props.style}}" class="{{i.props.class}}" bindtap="{{i.props.bindtap}}" > <block wx:for="{{i.children}}" wx:key="id"> <template is="{{'TPL_' + (tid + 1) + '_CONTAINER'}}" data="{{i: item, a: a, tid: tid + 1 }}" /> </block> </view> </template> <template name="TPL_3_view"> <view style="{{i.props.style}}" class="{{i.props.class}}" bindtap="{{i.props.bindtap}}" > <block wx:for="{{i.children}}" wx:key="id"> <template is="{{'TPL_' + (tid + 1) + '_CONTAINER'}}" data="{{i: item, a: a, tid: tid + 1 }}" /> </block> </view> </template> ... ...
至此,就可以真正實(shí)現(xiàn) React 代碼運(yùn)行到小程序了,可以在項(xiàng)目源碼里執(zhí)行npm run build:runtime
看看效果。運(yùn)行時方案優(yōu)點(diǎn)是無語法限制,(不信的話,可以在本項(xiàng)目里隨便寫各種動態(tài)寫法試試哦),而缺點(diǎn)時性能比較差,主要原因是因?yàn)槠?code>setData數(shù)據(jù)量比較大(上文已經(jīng)貼出的JSON
數(shù)據(jù),妥妥的比編譯時方案大),因此性能就比編譯時方案差。當(dāng)然了,業(yè)界針對運(yùn)行時方案也有做大量的性能優(yōu)化,比如局部更新、虛擬列表等,由于篇幅問題,這里就不一一講解(代碼中也沒有實(shí)現(xiàn))。
總結(jié)
本文以最簡實(shí)現(xiàn)方式講述了 React 構(gòu)建小程序兩種實(shí)現(xiàn)方案,這兩種方案優(yōu)缺點(diǎn)分明,都有各自的優(yōu)勢,對于追求性能好場的場景,編譯時方案更為合適。對于著重開發(fā)體驗(yàn)且對性能要求不高的場景,運(yùn)行時方案為首選。如果想了解更多源碼實(shí)現(xiàn),可以去看下 Taro、Remax 官方源碼,歡迎互相討論。
項(xiàng)目地址
https://github.com/canfoo/react-wxapp
【相關(guān)學(xué)習(xí)推薦:小程序開發(fā)教程】
The above is the detailed content of How to build applets in React? Two implementation solutions shared. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

PHP, Vue and React: How to choose the most suitable front-end framework? With the continuous development of Internet technology, front-end frameworks play a vital role in Web development. PHP, Vue and React are three representative front-end frameworks, each with its own unique characteristics and advantages. When choosing which front-end framework to use, developers need to make an informed decision based on project needs, team skills, and personal preferences. This article will compare the characteristics and uses of the three front-end frameworks PHP, Vue and React.

Integration of Java framework and React framework: Steps: Set up the back-end Java framework. Create project structure. Configure build tools. Create React applications. Write REST API endpoints. Configure the communication mechanism. Practical case (SpringBoot+React): Java code: Define RESTfulAPI controller. React code: Get and display the data returned by the API.

Vue.js is suitable for small and medium-sized projects and fast iterations, while React is suitable for large and complex applications. 1) Vue.js is easy to use and is suitable for situations where the team is insufficient or the project scale is small. 2) React has a richer ecosystem and is suitable for projects with high performance and complex functional needs.

Netflixusesacustomframeworkcalled"Gibbon"builtonReact,notReactorVuedirectly.1)TeamExperience:Choosebasedonfamiliarity.2)ProjectComplexity:Vueforsimplerprojects,Reactforcomplexones.3)CustomizationNeeds:Reactoffersmoreflexibility.4)Ecosystema

React combines JSX and HTML to improve user experience. 1) JSX embeds HTML to make development more intuitive. 2) The virtual DOM mechanism optimizes performance and reduces DOM operations. 3) Component-based management UI to improve maintainability. 4) State management and event processing enhance interactivity.

The React ecosystem includes state management libraries (such as Redux), routing libraries (such as ReactRouter), UI component libraries (such as Material-UI), testing tools (such as Jest), and building tools (such as Webpack). These tools work together to help developers develop and maintain applications efficiently, improve code quality and development efficiency.

1. Open the WeChat mini program and enter the corresponding mini program page. 2. Find the member-related entrance on the mini program page. Usually the member entrance is in the bottom navigation bar or personal center. 3. Click the membership portal to enter the membership application page. 4. On the membership application page, fill in relevant information, such as mobile phone number, name, etc. After completing the information, submit the application. 5. The mini program will review the membership application. After passing the review, the user can become a member of the WeChat mini program. 6. As a member, users will enjoy more membership rights, such as points, coupons, member-exclusive activities, etc.

Netflix uses React as its front-end framework. 1) React's componentized development model and strong ecosystem are the main reasons why Netflix chose it. 2) Through componentization, Netflix splits complex interfaces into manageable chunks such as video players, recommendation lists and user comments. 3) React's virtual DOM and component life cycle optimizes rendering efficiency and user interaction management.
