skip to content

What changed in FlashList v2 for React Native compared with v1, and what do you remove or rename when migrating?

level: middleimportance: should knowfreq 35%

answer

  1. New Architecture only, JavaScript only
  2. no more size estimates
  3. masonry became a prop
  4. ref type is FlashListRef
  5. content position kept by default

basics

~20 s

FlashList v2 runs only on the New Architecture, measures rows itself so estimatedItemSize and the other size estimates are gone, turns MasonryFlashList into a masonry prop, types refs as FlashListRef, and enables maintainVisibleContentPosition by default.

solid answer

~40 s

FlashList v2 was rebuilt as a JavaScript-only list for the **New Architecture**; on the legacy architecture it throws at import. It no longer needs size estimates, so `estimatedItemSize`, `estimatedListSize` and `estimatedFirstItemOffset` come out, and `overrideItemLayout` now sets only `span`. `MasonryFlashList` is replaced by a `masonry` prop on `FlashList` (`getColumnFlex` is not supported). Refs are typed `FlashListRef<T>` instead of `FlashList<T>`, and `scrollToIndex` returns a promise. `maintainVisibleContentPosition` is **on by default**, which can make items move when data is re-ordered; disable it with `{ disabled: true }`. New hooks - `useRecyclingState`, `useLayoutState`, `useMappingHelper` - handle recycled state, layout-changing state and keys in mapped children, and memoizing props passed to the list matters more than in v1.

go deeper

for a junior

Recall the headline changes: New Architecture only, no estimatedItemSize, masonry as a prop and FlashListRef for refs.

for a middle

Explain why estimates became unnecessary, and name the behaviours that changed under the same names, like default content-position keeping and memoization.

for a senior

Plan a v1 to v2 migration across many screens, including re-sortable grids, ref call sites that await scrollToIndex, and recycled-state resets.

for a principal

Weigh a library major version against the app's architecture and upgrade cadence, and schedule list migrations with the New Architecture move rather than as a separate project.

## Why v2 is a different list FlashList v1 relied on native code for layout and asked you for size estimates up front. v2 was rebuilt for React Native's **New Architecture**, where JavaScript can measure layout synchronously, and it became **JavaScript-only** with no native dependencies. That one change explains most of the migration: the list can measure real item sizes before paint, so the props that existed to guess sizes are gone. ## What to remove | v1 | v2 | |---|---| | `estimatedItemSize`, `estimatedListSize`, `estimatedFirstItemOffset` | removed - the list measures items itself | | `overrideItemLayout` setting `layout.size` | only `layout.span` is read | | `MasonryFlashList` component | `masonry` prop on `FlashList`; `getColumnFlex` is not supported | | `useRef<FlashList<T>>` | `useRef<FlashListRef<T>>` | | `CellContainer` export | not exported; use React Native's `View` | | `onBlankArea`, `disableAutoLayout`, `disableHorizontalListHeightMeasurement` | marked no longer supported or needed in the migration guide | ## Behaviour that changed under the same names - **New Architecture required.** `FlashList` v2 checks for the New Architecture when the module loads and throws "FlashList v2 is only supported on new architecture" otherwise. Since React Native 0.82 the legacy architecture cannot be enabled at all, so every current app qualifies; the check matters for older apps still on v1. - **`maintainVisibleContentPosition` is on by default.** The list keeps the visible content in place when items above it change size or are inserted, which smooths scrolling upward after a jump. The known-issues page notes the side effect: **re-ordering data can make items move**. For a marketplace grid the user re-sorts by price, pass `maintainVisibleContentPosition={{ disabled: true }}`. - **Props must be memoized.** The v2 docs say v1 was more selective about updating items, which developers often perceived as a bug; v2 re-renders when props change and relies on you to memoize them. - **`keyExtractor` is strongly recommended.** The migration notes say a valid `keyExtractor` prevents glitches from layout changes while scrolling upward. - **`scrollToIndex` returns a promise** on `FlashListRef`, resolving when the scroll completes. ## What was added - **`useRecyclingState(initial, deps, onReset?)`** - state that resets when deps change, without an extra render; the fix for stale state in recycled cells. - **`useLayoutState(initial)`** - like `useState`, but tells the list to re-layout when a change resizes the cell. - **`useMappingHelper()`** - its `getMappingKey(itemKey, index)` supplies keys for `.map()` children that do not break recycling. - **`onStartReached`**, **`masonry`** with `optimizeItemArrangement`, and RTL support. ## Improvements that need no code The v2 release notes also list changes you get simply by upgrading: - `scrollToIndex` and `scrollToItem` land more precisely. - Scrolling upward after an orientation change or a large jump no longer glitches the layout. - In a grid, side-by-side items of different heights now match the tallest one in the row. - Sticky headers use an Animated implementation, so small gaps between them while scrolling are gone. - `contentContainerStyle` is fully supported. ## A migration checklist 1. Confirm the app is on the New Architecture (any React Native 0.82+ app, including Expo SDK 57 on 0.86). 2. Bump `@shopify/flash-list` to v2 and delete the size-estimate props. 3. Replace `MasonryFlashList` with `<FlashList masonry numColumns={n} />`. 4. Change ref types to `FlashListRef<T>` and await `scrollToIndex` where the next step depends on it. 5. Reduce `overrideItemLayout` to span changes. 6. Memoize `renderItem`, `data` and other props; add a real `keyExtractor`. 7. Re-test screens whose data is re-ordered, and disable content-position keeping where it misbehaves. 8. Replace hand-written recycled-state resets with `useRecyclingState`. ## Interview angle The question usually probes whether the candidate knows **why** the estimates disappeared. A strong answer ties it to measurement: on the New Architecture the list can read real sizes before paint, so guessing is unnecessary - and a v2 list that still passes `estimatedItemSize` is a sign the migration was a version bump, not a review.

  • Why can FlashList v2 drop estimatedItemSize when v1 needed it?
    Because v2 is built for the New Architecture, where layout can be measured synchronously before paint. The list renders items, reads their real sizes and positions them before the frame is shown, so an up-front guess adds nothing. v1 had to lay cells out before it knew their sizes, and a bad estimate caused jumps and blank areas.
  • Items in a re-sortable FlashList v2 grid jump after sorting. What do you check first?
    `maintainVisibleContentPosition`, which v2 enables by default. The FlashList known-issues page says data re-ordering can make items move because of it. For a grid the user re-sorts, pass `maintainVisibleContentPosition={{ disabled: true }}`, or scroll to the top after a sort so there is no position to keep.

saying these in an interview costs you the question

  • FlashList v2 still needs estimatedItemSize for its first layout.
  • FlashList v2 runs on the legacy architecture with reduced performance.
  • A FlashList v2 ref is typed with the FlashList component type as in v1.
  • MasonryFlashList is still the way to build masonry layouts in v2.
  • FlashList v2 skips re-renders on its own, so props need no memoizing.