CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tarojs--runtime

Cross-platform runtime for Taro framework providing DOM/BOM polyfills and mini-program bridge functionality

Pending
Overview
Eval results
Files

framework-integration.mddocs/

Framework Integration APIs

DSL (Domain Specific Language) functions for integrating React components with mini-program platforms, including page configuration, component lifecycle management, and instance handling.

Overview

The framework integration module provides the bridge between React components and mini-program platforms by:

  • Page Configuration: Converting React components into mini-program pages
  • Component Configuration: Creating mini-program component definitions
  • Lifecycle Management: Handling page and component lifecycle events
  • Instance Registry: Managing page and component instances
  • Context Switching: Automatic state management for multi-page applications
  • Recursive Components: Dynamic component rendering support

Page Configuration

createPageConfig

import { createPageConfig } from '@tarojs/runtime'

function createPageConfig(
  component: ComponentClass,
  pageName?: string,
  data?: Record<string, any>,
  pageConfig?: PageConfig
): PageInstance

interface PageConfig {
  navigationBarTitleText?: string
  navigationBarBackgroundColor?: string
  navigationBarTextStyle?: 'black' | 'white'
  backgroundColor?: string
  backgroundTextStyle?: 'dark' | 'light'
  enablePullDownRefresh?: boolean
  onReachBottomDistance?: number
  [key: string]: any
}

interface PageInstance {
  // Page data
  data: Record<string, any>
  
  // Lifecycle methods  
  onLoad?(options: Record<string, unknown>): void
  onShow?(): void
  onHide?(): void  
  onReady?(): void
  onUnload?(): void
  onPullDownRefresh?(): void
  onReachBottom?(): void
  onPageScroll?(event: { scrollTop: number }): void
  onShareAppMessage?(event: any): any
  onShareTimeline?(): any
  
  // Custom methods
  [key: string]: any
}

Key Features

  • Lifecycle Integration: Automatically maps React lifecycle to mini-program lifecycle
  • Context Switching: Manages page context transitions and state preservation
  • Event Handling: Binds component methods to mini-program page events
  • Data Synchronization: Keeps React state in sync with mini-program data

Usage Examples

// Basic page configuration
class HomePage extends React.Component {
  state = { count: 0 }
  
  onIncrement = () => {
    this.setState({ count: this.state.count + 1 })
  }
  
  render() {
    return (
      <View onClick={this.onIncrement}>
        Count: {this.state.count}
      </View>
    )
  }
}

// Create mini-program page config
const pageConfig = createPageConfig(
  HomePage,
  'home',
  { title: 'Home Page' },
  { 
    navigationBarTitleText: 'Home',
    enablePullDownRefresh: true
  }
)

// Advanced page with lifecycle
class UserProfile extends React.Component {
  componentDidMount() {
    // Automatically called during onReady
    this.loadUserData()
  }
  
  onPullDownRefresh() {
    // Mini-program pull refresh handler
    this.refreshData().then(() => {
      wx.stopPullDownRefresh()
    })
  }
  
  onShareAppMessage() {
    return {
      title: 'Check out my profile',
      path: '/pages/profile/profile'
    }
  }
  
  loadUserData = async () => {
    const userData = await api.getUserProfile()
    this.setState({ user: userData })
  }
  
  refreshData = async () => {
    await this.loadUserData()
    // Update UI after data refresh
  }
  
  render() {
    return <UserProfileView user={this.state.user} />
  }
}

const profileConfig = createPageConfig(
  UserProfile, 
  'profile',
  { user: null },
  {
    navigationBarTitleText: 'Profile',
    enablePullDownRefresh: true,
    backgroundColor: '#f5f5f5'
  }
)

Component Configuration

createComponentConfig

import { createComponentConfig } from '@tarojs/runtime'

function createComponentConfig(config: ComponentConfig): ComponentInstance

interface ComponentConfig {
  // Lifecycle methods
  attached?(): void         // Component attached to DOM
  detached?(): void        // Component removed from DOM  
  ready?(): void           // Component ready (after attached)
  moved?(): void           // Component moved in DOM
  
  // Data and methods
  data?: Record<string, any>
  methods?: Record<string, Function>
  
  // Component options
  options?: {
    multipleSlots?: boolean
    addGlobalClass?: boolean
    virtualHost?: boolean
  }
  
  // Relations (component communication)
  relations?: Record<string, RelationConfig>
  
  // Observers (data watchers)
  observers?: Record<string, Function>
  
  // External classes
  externalClasses?: string[]
}

interface ComponentInstance {
  data: Record<string, any>
  setData(data: Record<string, any>, callback?: () => void): void
  
  // Lifecycle methods
  attached?(): void
  detached?(): void
  ready?(): void
  moved?(): void
  
  // Custom methods
  [key: string]: any
}

Usage Examples

// Basic component configuration
const buttonComponent = createComponentConfig({
  data: {
    text: '',
    disabled: false
  },
  
  methods: {
    onTap() {
      if (!this.data.disabled) {
        this.triggerEvent('tap', { value: this.data.text })
      }
    }
  },
  
  attached() {
    console.log('Button component attached')
  },
  
  detached() {
    console.log('Button component detached')
  }
})

// Advanced component with relations
const listComponent = createComponentConfig({
  data: {
    items: []
  },
  
  relations: {
    './list-item': {
      type: 'child',
      linked(target) {
        // Child list-item component linked
        this.data.items.push(target)
      },
      unlinked(target) {
        // Child list-item component unlinked
        const index = this.data.items.indexOf(target)
        this.data.items.splice(index, 1)
      }
    }
  },
  
  observers: {
    'items.length': function(newLength) {
      console.log('Items count changed:', newLength)
    }
  },
  
  options: {
    multipleSlots: true,
    addGlobalClass: true
  },
  
  externalClasses: ['custom-class'],
  
  ready() {
    // Component ready for interaction
    this.updateItemsData()
  }
})

createRecursiveComponentConfig

import { createRecursiveComponentConfig } from '@tarojs/runtime'

function createRecursiveComponentConfig(config?: RecursiveConfig): ComponentInstance

interface RecursiveConfig {
  // Custom wrapper handling
  customWrapper?: boolean
  
  // Virtual host options
  virtualHost?: boolean
}

Key Features

  • Dynamic Rendering: Enables recursive component structures
  • Custom Wrappers: Supports platform-specific wrapper elements
  • Virtual Host: Optimizes component hierarchy for performance

Usage Examples

// Recursive component for tree structures
const treeComponent = createRecursiveComponentConfig({
  customWrapper: true,
  virtualHost: true
})

// Use in dynamic component rendering
const dynamicRenderer = createRecursiveComponentConfig()

Instance Management

Page Instance Registry

import { 
  getPageInstance, 
  injectPageInstance, 
  removePageInstance 
} from '@tarojs/runtime'

// Get page instance by ID
function getPageInstance(id: string): PageInstance | undefined

// Register page instance
function injectPageInstance(instance: PageInstance, id: string): void

// Unregister page instance  
function removePageInstance(id: string): void

Usage Examples

// Register page instance
const pageId = 'home-page-123'
injectPageInstance(homePageConfig, pageId)

// Retrieve page instance
const instance = getPageInstance(pageId)
if (instance) {
  // Access page data and methods
  console.log('Page data:', instance.data)
  instance.onShow?.()
}

// Clean up page instance
removePageInstance(pageId)

Current Instance

import { getCurrentInstance, Current } from '@tarojs/runtime'

// Get current runtime instance
function getCurrentInstance(): Current

interface Current {
  app: AppInstance | null      // Current app instance
  router: Router | null        // Current router state
  page: PageInstance | null    // Current page instance
  preloadData?: any           // Preloaded data
}

interface Router {
  params: Record<string, unknown> // Route parameters
  path: string                   // Current route path
  $taroPath: string             // Taro-specific path
  onReady: string               // Ready event key
  onHide: string                // Hide event key  
  onShow: string                // Show event key
  exitState?: any               // Page exit state
}

Usage Examples

// Get current runtime state
const current = getCurrentInstance()

// Access current page
if (current.page) {
  console.log('Current page data:', current.page.data)
  
  // Call page methods
  current.page.onShow?.()
}

// Access router information
if (current.router) {
  console.log('Current path:', current.router.path)
  console.log('Route params:', current.router.params)
  console.log('Taro path:', current.router.$taroPath)
}

// Access app instance
if (current.app) {
  console.log('App instance:', current.app)
}

// Access preloaded data
if (current.preloadData) {
  console.log('Preloaded data:', current.preloadData)
}

// React hook usage
function useCurrentInstance() {
  return getCurrentInstance()
}

// Component usage
function MyComponent() {
  const current = useCurrentInstance()
  
  useEffect(() => {
    console.log('Current router:', current.router)
  }, [current.router])
  
  return <div>Path: {current.router?.path}</div>
}

Lifecycle Event Keys

Event Key Generators

import { 
  getOnReadyEventKey, 
  getOnShowEventKey, 
  getOnHideEventKey 
} from '@tarojs/runtime'

// Generate unique event keys for page lifecycle
function getOnReadyEventKey(id: string): string
function getOnShowEventKey(id: string): string  
function getOnHideEventKey(id: string): string

Usage Examples

const pageId = 'user-profile'

// Generate lifecycle event keys
const readyKey = getOnReadyEventKey(pageId)    // "onReady_user-profile"
const showKey = getOnShowEventKey(pageId)      // "onShow_user-profile"  
const hideKey = getOnHideEventKey(pageId)      // "onHide_user-profile"

// Use in event registration
eventCenter.on(readyKey, () => {
  console.log('Page ready:', pageId)
})

eventCenter.on(showKey, () => {
  console.log('Page shown:', pageId)
})

eventCenter.on(hideKey, () => {
  console.log('Page hidden:', pageId)
})

Utility Functions

safeExecute

import { safeExecute } from '@tarojs/runtime'

function safeExecute(
  fn: Function | undefined,
  context?: any,
  ...args: any[]
): any

Safely executes lifecycle methods with error handling:

// Safe lifecycle execution
const pageInstance = getPageInstance('home')

// Safely call lifecycle methods
safeExecute(pageInstance?.onShow, pageInstance)
safeExecute(pageInstance?.onHide, pageInstance)

// With arguments
safeExecute(pageInstance?.onLoad, pageInstance, { id: '123' })

// Custom context  
safeExecute(customMethod, customContext, arg1, arg2)

stringify

import { stringify } from '@tarojs/runtime'

function stringify(data: any): string

Safely converts data to JSON string:

// Safe JSON stringification
const data = { name: 'John', age: 30, circular: null }
data.circular = data  // Circular reference

const json = stringify(data)  // Handles circular references
console.log('JSON:', json)

// Complex objects
const complexData = {
  date: new Date(),
  regex: /pattern/g,
  fn: function() { return 'test' },
  symbol: Symbol('test')
}

const safeJson = stringify(complexData)  // Safely serializes

getPath

import { getPath } from '@tarojs/runtime'

function getPath(node: TaroElement): string

Gets the dot-notation path for DOM updates:

// Get element path for updates
const element = document.getElementById('my-element')
const path = getPath(element)  // "root.cn.[0].cn.[2]"

// Use in manual updates
const rootElement = element._root
rootElement.ctx?.setData({
  [path + '.v']: 'new value'
})

Advanced Integration Patterns

Context Switching

The framework automatically handles page context switching:

// Automatic context management
class MultiPageApp {
  // Page A
  pageA = createPageConfig(PageAComponent, 'pageA', {
    // Page A state preserved automatically
    userData: null
  })
  
  // Page B  
  pageB = createPageConfig(PageBComponent, 'pageB', {
    // Page B state preserved automatically
    settings: {}
  })
}

// Context is automatically:
// 1. Saved when page hides (onHide)
// 2. Restored when page shows (onShow)  
// 3. Cleaned up when page unloads (onUnload)

Custom Lifecycle Hooks

// Custom lifecycle integration
class CustomLifecyclePage extends React.Component {
  // Standard React lifecycle
  componentDidMount() {
    // Called during mini-program onReady
  }
  
  componentWillUnmount() {
    // Called during mini-program onUnload
  }
  
  // Mini-program specific lifecycle
  onPullDownRefresh() {
    // Handle pull-to-refresh
  }
  
  onReachBottom() {
    // Handle scroll to bottom
  }
  
  onPageScroll(event) {
    // Handle page scroll
    console.log('Scroll position:', event.scrollTop)
  }
  
  onShareAppMessage(event) {
    // Handle share action
    return {
      title: 'Share title',
      path: '/pages/share/share'
    }
  }
}

Component Communication

// Parent-child component communication
const parentConfig = createComponentConfig({
  data: { message: 'Hello from parent' },
  
  methods: {
    sendToChild(data) {
      // Send data to child component
      this.selectComponent('#child').receiveFromParent(data)
    },
    
    receiveFromChild(event) {
      // Receive data from child component
      console.log('Child sent:', event.detail)
    }
  }
})

const childConfig = createComponentConfig({  
  data: { childData: 'Hello from child' },
  
  methods: {
    sendToParent() {
      // Send data to parent component
      this.triggerEvent('childEvent', { 
        message: this.data.childData 
      })
    },
    
    receiveFromParent(data) {
      // Receive data from parent
      this.setData({ parentMessage: data })
    }
  }
})

The framework integration APIs provide a seamless bridge between React development patterns and mini-program platforms, enabling cross-platform development with familiar React concepts while leveraging platform-specific capabilities.

Install with Tessl CLI

npx tessl i tessl/npm-tarojs--runtime

docs

bom.md

dom.md

framework-integration.md

index.md

types.md

utilities.md

tile.json