JS‑Native Communication and Rendering Flow in Mini‑Program Architecture Using React Reconciler

This article explains how JavaScript in the logic process of a mini‑program communicates with the native layer, details the bidirectional protocol, and describes the React‑based rendering pipeline, host configuration, and container mechanisms that enable DOM updates across logic and render processes.

Beike Product & Technology
Beike Product & Technology
Beike Product & Technology
JS‑Native Communication and Rendering Flow in Mini‑Program Architecture Using React Reconciler

The article begins by identifying two critical issues in mini‑program architecture: establishing communication between the JavaScript logic process and the native/render processes, and enabling DOM operations from the logic layer.

Logic Engine Communication

In the logic engine, a V8 (or JavaScriptCore) instance is created by native code, which then executes the mini‑program scripts. Native can directly call functions in V8, requiring JavaScript to register a global function V8CallJs for native callbacks. Conversely, JavaScript calls native functions by first registering a global function JsCallNative and implementing a JavaCallback interface on the Java side. When JsCallNative is invoked, the V8 engine pauses, native processes the request, and later returns results via V8CallJs, forming the callback‑heavy communication model used by early WeChat mini‑programs.

The article also discusses why early mini‑programs relied on callbacks instead of Promises, noting compatibility with the de‑facto standard set by WeChat.

Bidirectional Communication Protocol

The protocol encodes all cross‑language messages as JSON strings and includes a command ID to correlate asynchronous callbacks. The TypeScript type definition is shown below:

type Type_Protocol = {
  /** command id */
  id: number;
  /** command type */
  type: "JsCallV8" | "V8CallJs" | "V8CallWebview" | "WebviewCallV8";
  /** API name */
  apiName: string;
  /** JSON‑encoded argument list */
  argvListJson: string;
};

A sequence diagram (illustrated in the original article) visualizes the message flow between JS, native, and the webview.

Render Process in the Rendering Process

After defining the communication protocol for the logic process, the same model is reused for the rendering process, treating it as a simple JS‑bridge.

The final communication model becomes: Logic Process <--> Native <--> Render Process React Reconciler Integration

The article then shifts to the implementation of the render function in a Remax‑based mini‑program. It imports React, react‑reconciler, and a custom hostConfig, creates a ReactReconcilerInst, and wraps the container with a Fiber root. The three main steps are:

Initialize ReactReconcilerInst with the host config.

Create a Fiber container via ReactReconcilerInst.createContainer.

Update the container with the JSX element using ReactReconcilerInst.updateContainer.

Further analysis shows how the reconciler schedules updates, computes expiration times, and eventually calls beginWork, which dispatches to updateFunctionComponent or updateClassComponent. For class components, the reconciler replaces the component’s updater with classComponentUpdater, enabling it to capture setState calls. For function components, hooks such as useState resolve to a dispatcher stored in ReactCurrentOwner.currentDispatcher, which is swapped during the work loop to a hook‑aware dispatcher.

The article also explains how Rollup rewrites imports of shared/ReactSharedInternals to point to react/src/ReactSharedInternals, allowing the reconciler to intercept hook calls.

HostConfig and Container

The host config defines the bridge between the reconciler and the rendering target. In Remax, hostConfig implements methods such as createInstance, createTextInstance, and resetAfterCommit. Instances are represented by VNode objects that store an ID, type, props, and a reference to the container.

The container maintains an updateQueue of SpliceUpdate and SetUpdate commands. After each reconciler commit, resetAfterCommit triggers container.applyUpdate(), which serializes the queued updates to JSON and forwards them to the native layer, which then delivers them to the webview‑render process.

Webview‑Render Side

In the webview, the JSON updates are parsed into RawNode structures. SpliceUpdate replaces entire sub‑trees, while SetUpdate mutates individual attributes to avoid losing input focus. Event handlers are mapped to generated function names (e.g., click_1_handler) and bound via addEventListener. When an event fires, the webview sends the event name and target ID back to the JS core through the native bridge, where the original handler is invoked, causing state changes and a new render cycle.

Conclusion

The article concludes that the described communication and rendering pipeline solves the core data‑transfer challenges in mini‑programs, while acknowledging that further work remains for libraries, IDEs, and backend services.

mini-programjs-native communicationreact reconciler
Beike Product & Technology
Written by

Beike Product & Technology

As Beike's official product and technology account, we are committed to building a platform for sharing Beike's product and technology insights, targeting internet/O2O developers and product professionals. We share high-quality original articles, tech salon events, and recruitment information weekly. Welcome to follow us.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.