Rendering Process and Lifecycle

Due to Lynx's dual-thread architecture, ReactLynx's rendering process and component lifecycle differ from traditional React. This design aims to address mobile performance bottlenecks by properly distributing tasks between threads to ensure rendering performance and interaction fluidity.

Rendering Process

Lifecycle Flowchart

First-Screen Rendering Optimization

To solve the slow first-screen loading problem of traditional web applications, Lynx adopts an innovative rendering strategy: when the application starts, the main thread completes the first-screen rendering to ensure the fastest possible initial display. Meanwhile, the background thread performs a parallel rendering and builds a node tree structure, then compares the tree structures from both threads to ensure consistency for handling subsequent updates and synchronizing to the main thread's node tree.

Dual-Thread Architecture Design

After the first-screen rendering is complete, ReactLynx's dual-thread architecture enhances overall performance through clear responsibility division. Component lifecycle management and user code execution will only occur in the background thread. After the node tree is updated in the background thread, the background thread will send a message to notify the main thread. The main thread is responsible for updating the main thread's node tree structure according to instructions from the background thread, calculating layouts, rendering the UI, and executing user-written main thread scripts.

This precise division of labor allows each thread to focus on its core responsibilities, preventing complex user logic from blocking UI responses, ensuring the normal operation of component lifecycles and state management.

Lifecycle Specifics

In ReactLynx, all lifecycle hooks execute asynchronously in the background thread, so they do not have synchronous blocking render characteristics. This means ReactLynx does not support useLayoutEffect. As a current alternative, you can use the element's main-thread:bindlayoutchange event to obtain layout results and set corresponding properties.

Here's a simple example modified from Measuring layout before the browser repaints the screen to help you use this more easily:

Special Characteristics of<list /> Child Components

The <list /> element has on-demand loading and node reuse characteristics. When a <list /> element is created, all its child component JS object instances are created together, but the corresponding actual elements (UI) are not immediately generated. Instead, they are created or reused only when the <list /> is about to scroll to the corresponding position. Therefore, special attention is needed regarding the timing of child component lifecycle triggers.

Timing ofuseEffect andref Callback Functions

The useEffect callback function executes strictly after component creation and data updates. Even if the component is not displayed on the screen (resulting in the actual UI node not being created or having entered the reuse pool), useEffect will still trigger its callback function.

The ref callback accurately reflects the state of UI elements inside <list />. When an element is about to scroll into view, the ref callback function is triggered, and when the element scrolls out of view, the ref cleanup function is triggered.

Based on this characteristic, if you need to handle node references, we recommend using ref callbacks instead of useEffect callbacks. This allows for more accurate tracking of node states and ensures components work properly whether they are in a <list /> or not.

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.