-
Notifications
You must be signed in to change notification settings - Fork 6
Description
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:
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