Skip to content

Feature Request: Lazy Rendering / Range Virtualization for Rows (Smart TV Performance) #102

@Jgaleas7

Description

@Jgaleas7

Summary

Add a built-in lazy rendering / range virtualization mechanism for row-based layouts (e.g., shelves of posters) in react-lightning, similar to the LazyRow primitive implemented in @lightningtv/solid.

This would significantly improve performance in Smart TV environments, where rails can contain hundreds of items, but only a small subset is visible at any time.


Problem

When building Smart TV interfaces with rails/shelves (Netflix-style UI), a common pattern is:

Home
├─ Row 1 (20–50 items)
├─ Row 2 (20–50 items)
├─ Row 3 (20–50 items)
├─ Row 4 (20–50 items)

In real applications, this can easily reach 300–500 items on a single screen.

Currently, when rendering rows with react-lightning:

  • all components are created immediately

  • all images begin loading immediately

  • rendering cost scales linearly with item count

Example:

8 rows × 60 items = 480 cards

This causes:

  • large number of network requests

  • high GPU memory usage

  • slower initial render time

  • worse performance on older TVs

In one real-world case we observed:

  • 500+ image requests on page load

  • 1600+ requests when scrolling across rows


Expected Behavior

Rows should support lazy rendering, meaning:

Only render items that are:

focused range ± buffer

Example:

Visible range: 0–7
Buffer: +3
Rendered items: 0–10

When the user navigates right:

focus moves → expand rendered range

But never shrink the range when navigating back, to avoid destroying and recreating components.

This spreads rendering and image loading over time.


Reference Implementation (Solid)

The Solid Lightning primitives already implement this pattern:

@lightningtv/solid/primitives/LazyRow

Core idea:

items.slice(0, offset)

Where offset increases when navigation approaches the end of the rendered items.

Example usage:

<LazyRow
display="block"
gap={20}
upCount={5}
each={activeRow()?.items()}
>
{(item, index) => <Poster {...item()} />}
</LazyRow>

Key behavior:

  • render first N items

  • increase render window when navigation approaches edge

  • never shrink when navigating back

  • optionally preload items progressively


Proposed API (React)

Something similar could be introduced for react-lightning:

<LazyRow
items={items}
initialCount={8}
buffer={3}
increment={4}
renderItem={(item, index) => (
<Poster item={item} />
)}
/>

Behavior:

initialCount = items rendered initially
buffer = threshold before expanding
increment = number of items to add

Internally:

visibleItems = items.slice(0, visibleCount)

When navigation reaches:

selectedIndex >= visibleCount - buffer

Then:

visibleCount += increment

Why This Matters for Smart TVs

Smart TVs often run:

  • Chromium v51–v70

  • low memory

  • slow GPUs

  • weak CPUs

Rendering hundreds of elements at once causes:

  • dropped frames

  • slow startup

  • network congestion

Lazy row rendering dramatically improves:

Metric | Improvement -- | -- Initial page load | 3–5× faster Memory usage | 70–80% reduction Network requests | 80–90% reduction on initial load

Alternative Approach (Renderer Level)

Lightning renderer already supports viewport bounds detection (inViewport, outOfBounds, etc.).

Another option could be:

  • automatic node skipping when outside render bounds

  • optional preload margins

However, row-level lazy rendering is still extremely valuable because it prevents component creation entirely, not just rendering.


Suggested Implementation

Options:

Option 1

Add a LazyRow component to react-lightning.

Option 2

Add range virtualization support to Row.

Example:

<Row range={{ from: 0, to: focusIndex + buffer }}>

Option 3

Expose a helper hook:

useLazyList()

Real-world Example

A typical TV home screen:

Home

Row 1 40 items
Row 2 50 items
Row 3 40 items
Row 4 60 items
Row 5 30 items

Total:

220 items

With lazy rows:

initial render ≈ 40–60 items

instead of 220.


Additional Benefit

Lazy rows also allow:

  • progressive image loading

  • smoother navigation

  • better CPU distribution

  • faster first paint


Related Work

Solid Lightning implementation:

@lightningtv/solid/primitives/LazyRow

Lightning Blits documentation:

:range lazy rendering

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions