Skip to content

feat: add MiniFlatList, a minimal FlatList-like list - #2

Merged
mdjastrzebski merged 4 commits into
mainfrom
claude/stacked-prs-followup-jgwa6e
Oct 6, 2026
Merged

mdjastrzebski merged 4 commits into
mainfrom
claude/stacked-prs-followup-jgwa6e

Conversation

@mdjastrzebski

@mdjastrzebski mdjastrzebski commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Stacked on #1. The base is #1's branch, so this diff shows only the new work. Once #1 merges, I'll move the base to main.

Summary

Adds MiniFlatList, a separate component in src/MiniFlatList/ that adds the core ideas of React Native's FlatList on top of NaiveList. NaiveList is unchanged and stays the simplest version.

Prop Default What it does
keyExtractor item.key → item.id → index Keys the items and their cached sizes, so sizes survive inserts and reorders
extraData – Changing it re-renders every item (cells are memoized)
initialNumToRender 10 Items rendered before the viewport is measured. They stay rendered, so scrolling back to the top shows them instantly
windowSize 21 Area kept rendered, in viewports, centered on the visible one
maxToRenderPerBatch 10 Most new items added in one update
updateCellsBatchingPeriod 50 ms Delay between updates that only fill the area off screen

The defaults match FlatList.

How it works

  • Scroll offset in a ref. Scrolling does not re-render the list while the visible items are already rendered. If the visible area is blank, the list renders right away. This mirrors the high- and low-priority update paths of VirtualizedList.
  • Batches. computeRenderWindow always renders the visible items, then grows toward windowSize viewports, adding at most maxToRenderPerBatch items that are not already rendered. Items that are already rendered and still inside the target are kept at no cost. After each commit, an effect schedules the next batch. The chain stops once a batch leaves the window unchanged, the same pattern as componentDidUpdate → _scheduleCellsToRenderUpdate.
  • Initial items stay mounted. addInitialItems puts the first initialNumToRender items in front of the render window and removes any overlap. The list renders the initial items, a spacer, the window and a tail spacer. This is FlatList's scroll-to-top optimization, which it keeps in the "initial region" of its render mask.
  • Memoized cells. A new batch renders only the new items. renderItem must be stable for this to work, as in FlatList.
  • Offsets and binary search. computeItemOffsets builds the start offsets once per render. findItemsInArea finds the items in an area with binary search. Unmeasured items count as the average measured size.

The pure logic lives in item-offsets.ts and render-window.ts, and is unit tested apart from React.

Not included (FlatList features for later PRs)

ItemSeparatorComponent, ListHeaderComponent, ListFooterComponent and ListEmptyComponent, onEndReached, getItemLayout, initialScrollIndex and scrollToIndex, onViewableItemsChanged, horizontal, inverted, and clamping the tail spacer to the last measured item.

Other changes

Testing

  • yarn typecheck, yarn lint and yarn test pass: 36 tests in total, 26 of them new.
  • Component tests use fake timers to step through batches. They cover initialNumToRender (rendered first and kept after scrolling away), batch growth, the immediate render when the visible area is blank, sizes staying with their keys after a reorder, memoization with extraData, and empty data.
  • Not run on a device or simulator yet.

claude and others added 4 commits October 6, 2026 12:49
Builds on NaiveList with the core ideas of React Native's FlatList:

- keyExtractor (default key, then id, then index) keys items and their
  cached sizes, so sizes survive inserts and reorders. Unmeasured items
  count as the average measured size.
- initialNumToRender items are rendered before the viewport is measured.
- windowSize sets the rendered area in viewports.
- Batched rendering: the scroll offset lives in a ref, so scrolling does
  not re-render while the visible items are rendered. The off-screen area
  fills maxToRenderPerBatch items every updateCellsBatchingPeriod ms; a
  blank visible area renders right away.
- Cells are memoized and re-render only when their props or extraData
  change.
- Offsets are looked up with binary search.

The example app can switch between NaiveList and MiniFlatList.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZxDtj1CphSjr2V67rdmFP
Like FlatList, the first initialNumToRender items stay mounted after the
window moves away, so scrolling back to the top shows them instantly. A
spacer stands in for the items between them and the window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZxDtj1CphSjr2V67rdmFP
@mdjastrzebski
mdjastrzebski force-pushed the claude/stacked-prs-followup-jgwa6e branch from 4774797 to 95b8930 Compare October 6, 2026 11:03
@mdjastrzebski
mdjastrzebski changed the base branch from claude/minimal-flat-list-api-mkmand to main October 6, 2026 11:07
@mdjastrzebski
mdjastrzebski merged commit 453e9eb into main Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants