溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

React怎么構(gòu)建小程序

發(fā)布時間:2021-12-23 10:47:19 來源:億速云 閱讀:121 作者:iii 欄目:移動開發(fā)

這篇文章主要介紹“React怎么構(gòu)建小程序”,在日常操作中,相信很多人在React怎么構(gòu)建小程序問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”React怎么構(gòu)建小程序”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

項目描述

為了更清晰描述實現(xiàn)過程,我們把實現(xiàn)方案當(dāng)作一個項目來對待。
項目需求:使如下計數(shù)器功能的 React 代碼運行到微信小程序平臺。

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>
    )
  }
}

如果使用過 Taro 或者 Remax 等框架,對上述代碼應(yīng)該有似曾相識的感覺,上述代碼正式模仿這類框架的 React DSL 寫法。如果想迫切看到實現(xiàn)這個需求的效果,可點擊此項目源碼進行獲取源碼,然后根據(jù)提示運行項目,即可觀察到如下效果:

React怎么構(gòu)建小程序

到這里,就清楚了知道這個項目的需求以及最終實現(xiàn)結(jié)果是什么,接下來便是重點闡述從需求點到結(jié)果這個過程的具體實現(xiàn)。

實現(xiàn)方案

構(gòu)建小程序框架產(chǎn)物

開發(fā)過小程序的同學(xué)都知道,小程序框架包含主體和頁面,其中主體是由三個文件生組成的,且必須放在根目錄,這三個文件分別是: app.js (必需,小程序邏輯),app.json(必需,小程序公共配置),app.wxss(非必須,小程序公共樣式表)。所以要將 React 代碼構(gòu)建成小程序代碼,首先需要先生成app.jsapp.json文件。因為本次轉(zhuǎn)換未涉及到app.js文件,所以app.js內(nèi)容可以直接寫死 App({})代替。app.json是配置文件,可以直接在 React 工程新增一個app.config.js用來填寫配置內(nèi)容,即 React 代碼工程目錄如下:

├── src
│   ├── app.config.js          // 小程序配置文件,用來生成app.json內(nèi)容      
│   └── pages
│       └── index
│           ├── index.css
│           └── index.jsx      // React代碼,即上述計數(shù)器代碼
└── tsconfig.json

app.config.js內(nèi)容即是小程序全局配置內(nèi)容,如下:

module.exports = {
  pages: ['pages/index/index'],
  window: {
    navigationBarTitleText: 'react-wxapp',
    navigationBarBackgroundColor: '#282c34'
  }
};

有了這個配置文件,就可以通過如下方式生成app.jsapp.json文件。

/*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)容

小程序頁面則是由四種類型文件構(gòu)成,分別是js(必需,頁面邏輯)、wxml(必需,頁面結(jié)是構(gòu))、json(非必需、頁面配置)、wxss(非必需、頁面樣式表)。而React代碼轉(zhuǎn)小程序,主要是考慮如何將React代碼轉(zhuǎn)換程序?qū)?yīng)的jswxml類型文件,后文會詳細闡述。

React運行到小程序平臺方案分析

實現(xiàn)React代碼運行到小程序平臺上主要有兩種方式,一種是編譯時實現(xiàn),一種是運行時實現(xiàn),如果你已經(jīng)查看的本項目項目源碼,就可以發(fā)現(xiàn)源碼里也體現(xiàn)出了這兩種方式(編譯時實現(xiàn)目錄:packages/compile-core;運行時實現(xiàn)目錄:packages/runtime-core)。

編譯時方式主要通過靜態(tài)編譯將 JSX 轉(zhuǎn)換成小程序?qū)?yīng)的 template 來實現(xiàn)渲染,類似 Taro1.0 和 2.0,此方式性能接近原生小程序,但是語法卻有很大的限制。運行時實現(xiàn)是通過react-reconciler重新在小程序平臺定義一個 React 渲染器,使得 React 代碼可以真正運行到小程序里,類似 Taro3.0、Remax 等,因此這種方式無語法限制,但是性能會比較差。本項目源碼正是參照 Taro、Remax 這類框架源碼并簡化很多細節(jié)進行實現(xiàn)的,因此這個項目源碼只是適合來學(xué)習(xí)的,并不能投入實際業(yè)務(wù)進行使用。

接下來將分別講述如何通過編譯時和運行時這兩種方式來實現(xiàn) React 運行到小程序平臺。

編譯時實現(xiàn)

在講述具體實現(xiàn)流程之前,首先需要了解下編譯時實現(xiàn)這個名詞的概念,首先這里的編譯并非傳統(tǒng)的高大上“編譯”,傳統(tǒng)意義上的編譯一般將高級語言往低級語言進行編譯,但這里只是將同等水平語言轉(zhuǎn)換,即將javascript代碼字符串編譯成另一種javascript代碼字符串,因此這里的編譯更類似于“轉(zhuǎn)譯”。其次,雖然這里稱編譯時實現(xiàn),并非所有實現(xiàn)過程都是編譯的,還是需要少部分實現(xiàn)需要運行時配合,因此這種方式稱為重編譯輕運行方式更為合適。同樣的,運行時實現(xiàn)也含有少量編譯時實現(xiàn),亦可稱為重運行輕編譯方式。

為了方便實現(xiàn)將javascript代碼字符串編譯成另一種javascript代碼字符串,這里直接采用Babel工具,由于篇幅問題,這里就不詳細講述Babel用法了,如果對Babel不熟的話,可以看看這篇文章簡單了解下(沒錯,就是給自己打廣告)。接下來我們來分析編譯時實現(xiàn)步驟有哪些:

1. JSX轉(zhuǎn)換成對應(yīng)小程序的模板

React是通過JSX來渲染視圖的,而小程序則通過wxml來渲染視圖,要將 React 運行到小程序上,其重點就是要如何實現(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)換遠不止上面這些類型,如果要保證開發(fā)者可以使用各種JSX語法開發(fā)小程序,就需要盡可能窮舉出所有語法轉(zhuǎn)換規(guī)則,否則很可能開發(fā)者用了一個寫法就不支持轉(zhuǎn)換。而事實是,有些寫法(比如動態(tài)生成JSX片段等等)是根本無法支持轉(zhuǎn)換,這也是前文為什么說編譯時實現(xiàn)方案的缺點是語法有限制,開發(fā)者不能隨意編碼,需要受限于框架本身開發(fā)規(guī)則。

由于上述需要轉(zhuǎn)換JSX代碼語法相對簡單,只需要涉及幾種簡單語法規(guī)則轉(zhuǎn)換,這里直接貼出轉(zhuǎn)換后的wxml結(jié)果如下,對應(yīng)的實現(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. 運行時適配

如前文所說,雖然這個方案稱為編譯時實現(xiàn),但是要將React代碼在小程序平臺驅(qū)動運行起來,還需要在運行時做下適配處理。適配處理主要在小程序js邏輯實現(xiàn),內(nèi)容主要有三塊:數(shù)據(jù)渲染、事件處理、生命周期映射。

小程序js邏輯是通過一個object參數(shù)配置聲明周期、事件等來進行注冊,并通過setData方法觸發(fā)視圖渲染:

Component({
  data: {},
  onReady () { this.setData(..) },
  handleClick () {}
})

而計數(shù)器React代碼是通過class聲明一個組件邏輯,類似:

class CustomComponent extends Component {
  state = { }
  componentDidMount() { this.setState(..)  }
  handleClick () { }
}

從上面兩段代碼可以看出,小程序是通過object聲明邏輯,React 則是通過class進行聲明。除此之外,小程序是通過setData觸發(fā)視圖(wxml)渲染,React 則是通過 setState 觸發(fā)視圖(render方法)渲染。所以要使得 React 邏輯可以運行到小程序平臺,可以加入一個運行時墊片,將兩者邏輯寫法通過墊片對應(yīng)起來。再介紹運行時墊片具體實現(xiàn)前,還需要對上述 React 計數(shù)器代碼進行簡單的轉(zhuǎn)換處理,處理完的代碼如下:

import React, { Component } from "../../npm/app.js";  // 1.app.js為墊片實現(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
                                                      // 提供給小程序進行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.使用運行時墊片提供的createPage
                                                      // 方法進行初始化
                                                      // 方法進行初始化

如上代碼,需要處理的地方有4處:

  • Component進行重寫,重寫邏輯在運行時墊片文件內(nèi)實現(xiàn),即app.js,實現(xiàn)具體邏輯后文會貼出。

  • 將原本JSX的點擊事件對應(yīng)的回調(diào)方法名稱進行收集,以便在運行時墊片在小程序平臺進行事件注冊。

  • 因為原本render方法內(nèi)JSX片段轉(zhuǎn)換為wxml了,所以這里render方法可將JSX片段進行刪除。另外因為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進行返回。

  • 使用運行時墊片提供的createPage方法進行初始化(createPage方法實現(xiàn)具體邏輯后文會貼出),同時通過小程序平臺提供的Page方法進行注冊,從這里可得知createPage方法返回的數(shù)據(jù)肯定是一個object類型。

運行時墊片(app.js)實現(xiàn)邏輯如下:

export class Component {                             // 重寫Component的實現(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進行更新
}
export function createPage(ComponentClass) {         // createPage實現(xiàn)邏輯
  const componentInstance = new ComponentClass()     // 實例化傳入進來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方法具體實現(xiàn)邏輯如上代碼所示。

Component內(nèi)聲明的state會執(zhí)行一個update方法,update方法里主要是將 React 產(chǎn)生的新state和舊state進行合并,然后通過上文說的createData方法獲取到合并后的最新state,最新的state再傳遞給小程序進行setData,從而實現(xiàn)小程序數(shù)據(jù)渲染。

createPage方法邏輯首先是將 React 組件實例化,然后構(gòu)建出一個小程序邏輯的對應(yīng)字面量,并將 React 組件實例相關(guān)方法和這個小程序邏輯對象字面量進行綁定:其次進行生命周期綁定:在小程序onReady周期里出發(fā) React 組件對應(yīng)的componentDidMount生命周期;最好進行事件綁定:通過上文提到的回調(diào)事件名,取出React 組件實例內(nèi)的對應(yīng)的事件,并將這些事件注冊到小程序邏輯的對應(yīng)字面量內(nèi),這樣就完成小程序平臺事件綁定。最后將這個對象字面量返回,供前文所說的Page方法進行注冊。

到此,就可以實現(xiàn) React 代碼運行到小程序平臺了,可以在項目源碼里執(zhí)行 npm run build:compile 看看效果。編譯時實現(xiàn)方案主要是通過靜態(tài)編譯JSX代碼和運行時墊片結(jié)合,完成 React 代碼運行到小程序平臺,這種方案基本無性能上的損耗,且可以在運行時墊片做一些優(yōu)化處理(比如去除不必要的渲染數(shù)據(jù),減少setData數(shù)據(jù)量),因此其性能與使用小程序原生語法開發(fā)相近甚至某些場景會更優(yōu)。然而這種方案的缺點就是語法限制問題(上文已經(jīng)提過了),使得開發(fā)并不友好,因此也就有了運行時實現(xiàn)方案的誕生。

運行時實現(xiàn)

從上文可以看出,編譯時實現(xiàn)之所以有語法限制,主要因為其不是讓 React 真正運行到小程序平臺,而運行時實現(xiàn)方案則可以,其原理是在小程序平臺實現(xiàn)一個 React 自定義渲染器,用來渲染 React 代碼。這里我們以 remax 框架實現(xiàn)方式來進行講解,本項目源碼中的運行時實現(xiàn)也正是參照 remax 框架實現(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 平臺的渲染器,主要負責(zé)將 React 執(zhí)行后的Vitrual DOM數(shù)據(jù)渲染到 Web 平臺。同樣的,React 要渲染到 Native,也有一個針對 Native 平臺的渲染器:React Native。
React實現(xiàn)多平臺方式,是在每個平臺實現(xiàn)一個React渲染器,如下圖所示。

React怎么構(gòu)建小程序

而如果要將 React 運行到小程序平臺,只需要開發(fā)一個小程序自定義渲染器即可。React 官方提供了一個react-reconciler 包專門來實現(xiàn)自定義渲染器,官方提供了一個簡單demo重寫了react-dom。

使用react-reconciler實現(xiàn)渲染器主要有兩步,第一步:實現(xiàn)渲染函數(shù)(render方法),類似ReactDOM.render方法:

import ReactReconciler from 'react-reconciler'
import hostConfig from './hostConfig'      // 宿主配置

// 創(chuàng)建Reconciler實例, 并將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實現(xiàn)宿主配置(HostConfig),HostConfig是宿主環(huán)境提供一系列適配器方案和配置項,定義了如何創(chuàng)建節(jié)點實例、構(gòu)建節(jié)點樹、提交和更新等操作,完整列表可以點擊查看。值得注意的是在小程序平臺未提供DOM API操作,只能通過setData將數(shù)據(jù)傳遞給視圖層。因此Remax重新定義了一個VNode類型的節(jié)點,讓 React 在reconciliation過程中不是直接去改變DOM,而先更新VNode,hostConfig文件內(nèi)容大致如下:

interface VNode {
  id: number;              // 節(jié)點 id,這是一個自增的唯一 id,用于標(biāo)識節(jié)點。
  container: Container;    // 類似 ReactDOM.render(<App />, document.getElementById('root') 中的第二個參數(shù)
  children: VNode[];       // 子節(jié)點。
  type: string | symbol;   // 節(jié)點的類型,也就是小程序中的基礎(chǔ)組件,如:view、text等等。
  props?: any;             // 節(jié)點的屬性。
  parent: VNode | null;    // 父節(jié)點
  text?: string;           // 文本節(jié)點上的文字
  appendChild(node: VNode): void;
  removeChild(node: VNode): void;
  insertBefore(newNode: VNode, referenceNode: VNode): void;
  ...
}

// 實現(xiàn)宿主配置
const hostConfig = {

  ...
  // reconciler提交后執(zhí)行,觸發(fā)容器更新數(shù)據(jù)(實際會觸發(fā)小程序的setData)
  resetAfterCommit: (container) => {
    container.applyUpdate();
  },
  // 創(chuàng)建宿主組件實例,初始化VNode節(jié)點
  createInstance(type, newProps, container) {
    const id = generate();
    const node = new VNode({ ... });
    return node;
  },
  // 插入節(jié)點
  appendChild(parent, child) {
    parent.appendChild(child);
  },
  // 
  insertBefore(parent, child, beforeChild) {
    parent.insertBefore(child, beforeChild);
  },
  // 移除節(jié)點
  removeChild(parent, child) {
    parent.removeChild(child);
  }
  
  ...
  
};

除了上面的配置內(nèi)容,還需要提供一個容器用來將VNode數(shù)據(jù)格式化為JSON數(shù)據(jù),供小程序setData傳遞給視圖層,這個容器類實現(xiàn)如下:

class Container {
  constructor(context) {
    this.root = new VNode({..});   // 根節(jié)點
  }

  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)實現(xiàn)完小程序渲染器了,為了使代碼跑起來,還需要通過靜態(tài)編譯改造下 React 計數(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代碼在小程序真正運行起來了,但是這里我們還有個流程沒介紹,上述Container類的applyUpdate方法中生成的頁面JSON數(shù)據(jù)要如何更新到視圖?首先我們先來看下這個JSON數(shù)據(jù)長什么樣子:

// 篇幅問題,這里只貼部分數(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ù),其實是一棵類似Tree UI的數(shù)據(jù),要將這些數(shù)據(jù)渲染出頁面,可以使用小程序提供的Temlate進行渲染,由于小程序模板遞歸嵌套會有問題(微信小程序平臺限制),因此需要提供多個同樣組件類型的模板進行遞歸渲染,代碼如下:

<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>
 
...
...

至此,就可以真正實現(xiàn) React 代碼運行到小程序了,可以在項目源碼里執(zhí)行npm run build:runtime看看效果。

到此,關(guān)于“React怎么構(gòu)建小程序”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI