ReactLynx Rendering Pipeline

This article uses the hello-world project as an example to explain the ReactLynx rendering process in detail:

  • Demonstrate the complete execution flow from the first-frame render to component updates in ReactLynx
  • Understand the event distribution and timing relationships of each key stage in the Trace view
  • Learn how to use the Trace tool to accurately locate performance bottlenecks in the rendering process
Trace Render Pipeline

First Screen Rendering

First Screen Rendering includes stages such as downloading the Bundle, loading the bundle, and drawing.

Download Bundle

After the page starts, it first downloads the Bundle。

Trace Render Pipeline

Load Bundle

Once the bundle is downloaded, it enters the loading stage.

Trace Render Pipeline

Parse Bundle

During the bundle loading stage, the content of the bundle—such as CSS stylesheets, scripts, and page configurations—is first parsed

Trace Render Pipeline

Execute MTS

After parsing the bundle, the Engine thread virtual machine executes the MTS.

Trace Render Pipeline

Execute BTS

Meanwhile, the background thread virtual machine loads, parses, and executes the BTS.

Execute Background Script

During BTS execution, you can observe the creation process of components.

Background Thread Create Component
TIP

The background thread does not block the Engine thread’s Element tree construction, resolve, layout, and other flows.

Construct the Element Tree

During the Element tree construction stage, the Element PAPI is called to convert the page structure into an Element tree.

Taking the hello-world project as an example, the first frame creates 1 page element, 6 view elements, 2 image elements, and 5 text elements.

<page>
  <view className="Background" />
  <view className="App">
    <view className="Banner">
      <view className="Logo" bindtap={onTap}>
        <image src={lynxLogo} className="Logo--lynx" />
      </view>
      <text className="Title">React</text>
      <text className="Subtitle">on Lynx</text>
  </view>
  <view className="Content">
    <image src={arrow} className="Arrow" />
    <text className="Description">Tap the logo and have fun!</text>
    <text className="Hint">
      Edit<text style={{ fontStyle: "italic" }}>{" src/App.tsx "}</text>
      to see updates!
    </text>
  </view>
  <view style={{ flex: 1 }}></view>
  </view>
</page>

In Trace, you can observe the complete process of creating Elements and setting their Events, Classes, and other attributes.

Trace Render Pipeline

Resolve

During the Resolve stage, the Element’s class, inline styles, and other attributes are parsed to determine the Element’s style, and the layout node tree is created. As shown below, the Resolve stage covers the complete execution flow and the parsing of styles for <view className="Background" />.

Trace Render Pipeline

Layout

The layout stage measures and lays out the layout nodes. The following example shows the layout process of the <text>Tap the logo and have fun!</text> node.

Trace Render Pipeline

Flush

After the layout is complete, platform UIs are created, with various attributes and layout information set.

Create Platform UI

:::tip Element nodes containing only layout attributes will not create platform UI nodes. Nested text will be merged with their parent text node to create a single platform UI. ::

In the hello-world project, the following nodes create platform UI on the first screen:

<page>
  <view className="Background" />
  <view className="Banner">
    <view className="Logo" bindtap="{onTap}">
      <image src="{lynxLogo}" className="Logo--lynx" />}
    </view>
  </view>
  <text className="Title">React</text>
  <text className="Subtitle">on Lynx</text>
  <image src="{arrow}" className="Arrow" />
  <text className="Description">Tap the logo and have fun!</text>
  <text className="Hint"> Edit " src/App.tsx " to see updates!</text>
</page>

Draw

When the system’s rendering callback occurs, the platform UI completes its first-screen drawing.

Draw Platform UI

Update Rendering Process

Taking the hello-world project as an example, clicking the Logo triggers an update, which demonstrates the component update rendering flow.

Draw Platform UI

Trigger the Click Event

After clicking the Logo, LynxView processes the click event and sends the event to the background thread, triggering the corresponding node’s click event handler.

To better observe the execution timing of the click event callback in Trace, you can use the Trace API to add custom Trace events.

const onTap = useCallback(() => {
  'background only';
  lynx.performance.profileStart('onTap');
  setAlterLogo(!alterLogo);
  lynx.performance.profileEnd();
}, [alterLogo]);
Touch Event Process

The App component updates the state of alterLogo in the click event callback.

Diff Component Diff

After updating the component state, the component diff process is triggered, and the image node changes:

<view className="Logo" bindtap="{onTap}">
  + <image src="{reactLynxLogo}" className="Logo--react" /> - -
  <image src="{lynxLogo}" className="Logo--lynx" />
</view>

The following image shows the diff process for the App component:

Component Diff Process

Component Update Synchronization

After the component diff is complete, the update information is synchronized to the Engine thread, driving subsequent UI changes. In Trace, clicking the CallLepusMethod event allows you to see the UI update process after component diff is complete.

Sync Diff To UI Thread

UI Update

The Engine thread shows the update process of the Element tree. As shown below, the Element tree removes one element and adds a new image element.

Sync Diff To UI Thread

After the Element update is complete, the layout and UI are updated again.

Sync Diff To UI Thread

Trigger useEffect Callback

After the Element tree update is complete, the background thread is notified to trigger the component’s useEffect callback.

To better observe the execution timing of the useEffect callback in Trace, use the Trace API to add custom trace events.

useEffect(() => {
  console.info('Hello, ReactLynx');
}, []);

useEffect(() => {
  lynx.performance.profileMark('useEffect', {
    args: { alterLogo: `${alterLogo}` },
  });
}, [alterLogo]);
useEffect Callback
Except as otherwise noted, this work is licensed under a Creative Commons Attribution 4.0 International License, and code samples are licensed under the Apache License 2.0.