Skip to content

feat: add TinyFlashList, a minimal FlashList with cell recycling - #3

Merged
mdjastrzebski merged 7 commits into
mainfrom
claude/minimal-flash-list
Oct 6, 2026
Merged

mdjastrzebski merged 7 commits into
mainfrom
claude/minimal-flash-list

Conversation

@mdjastrzebski

@mdjastrzebski mdjastrzebski commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds TinyFlashList, a minimal version of FlashList v2 (refs/flash-list). It keeps FlashList's core mechanisms and puts each one in a small file a reader can follow:

Mechanism File FlashList counterpart
A layout (offset, size) for every item. Unmeasured items use the average measured size. Binary search finds the items in an offset range layout-manager.ts LayoutManager.ts, LinearLayoutManager.ts, findVisibleIndex.ts
Engaged range: the viewport plus drawDistance (250 px) on each side engaged-indices.ts EngagedIndicesTracker.ts
Recycling: React keys are recycle keys. A key moves from an item that scrolled out to one that scrolled in, but only between items of the same getItemType render-stack.ts, ViewHolder.tsx RenderStackManager.ts, ViewHolder.tsx
Measure before paint: a layout effect measures every cell with synchronous measureLayout (Fabric) and re-renders until nothing moves (max 10 passes) TinyFlashList.tsx, measure-layout.ts effects in RecyclerView.tsx, measureLayout.ts
Absolutely positioned cells inside one view as tall as the content ViewHolder.tsx ViewHolder.tsx
Mutable state objects; React state only triggers re-renders TinyFlashList.tsx RecyclerViewManager.ts

src/TinyFlashList/README.md explains the algorithm in plain language and itemizes what is and is not implemented from FlashList. The main omissions are velocity projection and the direction-skewed buffer, progressive first render, bounded relayout, keyExtractor and scroll anchoring, the recycle-pool limit, and the rest of the API.

Other changes

  • measure-layout.web.ts: react-native-web's measureLayout is async, so on web DOM sizes are read directly (FlashList does the same).
  • The example app gets a TinyFlashList tab. Every 20th row is a section header, which gives getItemType two types to work with.
  • README usage section.

Known limitations

  • New architecture only, like FlashList v2.
  • renderItem must be stable, because ViewHolder is memoized.
  • Row state survives recycling. There is no useRecyclingState.
  • Inserting items above the viewport makes the content jump. Keys and layouts follow the index.

Testing

  • yarn typecheck, yarn lint and yarn test (59 tests) pass on the rebased branch.
  • There are unit tests for the layout manager, engaged range and render stack. The component tests mock measurement, as FlashList's tests do. One of them checks recycling: after a scroll from the top to item 35, 35 different items have been shown but only 20 cells were ever mounted.
  • Smoke-tested the web export of the example in headless Chromium. At scroll offsets 0, 3,000, 20,000 and 150,000 px, 15–19 cells were mounted, with no gaps, no overlaps and no console errors.
  • Not run on an iOS or Android device yet.

🤖 Generated with Claude Code

https://claude.ai/code/session_014zUjsSmEnFHTMD6LrCrjyQ

@mdjastrzebski
mdjastrzebski force-pushed the claude/minimal-flash-list branch from c7483ef to a2c61f7 Compare October 6, 2026 11:12
@mdjastrzebski mdjastrzebski changed the title feat: add MiniFlashList, a minimal FlashList with cell recycling feat: add TinyFlashList, a minimal FlashList with cell recycling Oct 6, 2026
@mdjastrzebski
mdjastrzebski changed the base branch from claude/minimal-flat-list-api-mkmand to main October 6, 2026 11:12
claude and others added 7 commits October 6, 2026 13:54
MiniFlashList keeps FlashList v2's core mechanisms in small, readable files:

- LinearLayoutManager: a layout for every item, estimates from the average
  measured size, binary search for the items in an offset range.
- computeEngagedRange: viewport plus drawDistance on each side.
- RenderStack: recycle keys reused across items of the same type.
- A layout effect that measures cells synchronously before paint and
  re-renders until the layout settles.

The example app can switch between NaiveList and MiniFlashList.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014zUjsSmEnFHTMD6LrCrjyQ
Explain recycling and the four render steps in plain language, and itemize
what is implemented from FlashList and what is not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014zUjsSmEnFHTMD6LrCrjyQ
@mdjastrzebski
mdjastrzebski force-pushed the claude/minimal-flash-list branch from db505c9 to 2d870d5 Compare October 6, 2026 12:08
@mdjastrzebski
mdjastrzebski merged commit 7aaf0ad into main Oct 6, 2026
6 checks passed
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