Skip to content

FlashList v2 causes infinite render loop ("Exceeded max renders without commit") on specific Android devices when nested in ScrollView #1966

@ertan95

Description

@ertan95

Description

When using FlashList v2 inside a nested scroll container (a ScrollView in my case), the list causes an infinite render loop and eventually crashes on specific Android devices (e.g. Oppo, Samsung).
The console logs show:

[WARN] Exceeded max renders without commit.
[ERROR] Error: Maximum update depth exceeded.
Replacing FlashList with a regular FlatList immediately fixes the problem — no re-renders, no warnings, and no crashes.

The issue only appears when FlashList is nested inside another scroll view and only on certain Android devices.

Current behavior

FlashList v2 triggers an infinite render loop on some Android devices (Oppo Find X2 Neo / Reno3 Pro, Samsung models).
The app crashes with Maximum update depth exceeded.
Internal components (ViewHolderInternal, ViewHolderCollection) keep re-rendering with props that are equal by value but different by reference.
The list only has 2 items — no duplicate keys and stable references.
The same component works perfectly on iOS and other Android devices.
Verified with why-did-you-render:

Image

Expected behavior

Not trigger infinite renders when data, keys, and layout props are stable.
Work correctly when nested inside a ScrollView (or at least not crash).
Match the behavior of FlatList, which works correctly in the same setup.

Reproduction

I have a vertical scroll list in my landing page like this:

import { ScrollView } from 'react-native-gesture-handler';
import StatsList from './StatsList'; // your StatsList component

const LandingPage = () => {
  return (
    <ScrollView>
      <StatsList />
    </ScrollView>
  );
};

Here is my StatsList component:

import { FlashList } from '@shopify/flash-list';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { shallowEqual } from 'react-redux';
import { ThemeName, XStack } from 'tamagui';

import { StatsCard } from '@/components/Common/Cards';
import { StatsData, useStats } from '@/components/LandingPage/Dashboard/hooks';
import { useAppSelector } from '@/store/store';
import { SCREEN_WIDTH } from '@/utils/constants';

const StatsList = () => {
  const SPACING = 5;
  const CELL_WIDTH = SCREEN_WIDTH * 0.54;
  const FULL_SIZE = CELL_WIDTH - SPACING;
  const { t } = useTranslation();
  const overviewMode = useAppSelector((state) => state.landing.overviewMode, shallowEqual);
  const appTheme = useAppSelector((state) => state.settings.theme, shallowEqual);

  const data = useStats(overviewMode);

  const renderItem = useCallback(
    ({ item }: { item: StatsData }) => {
      const theme = appTheme === 'light' ? ('pastell_beige' as ThemeName) : ('silver' as ThemeName);
      return (
        <XStack width={CELL_WIDTH} padding={SPACING}>
          <StatsCard
            hasProgressBar
            title={t(item.title)}
            value={item.value}
            maxValue={item.maxValue}
            subTitle={item.subTitle}
            subValue={item.subValue}
            theme={theme}
            brightGradient={appTheme === 'dark'}
          />
        </XStack>
      );
    },
    [appTheme, t, CELL_WIDTH] 
  );

  const keyExtractor = useCallback(
    (item: StatsData, index: number) => `${overviewMode}-${item.title}-${index}`,
    [overviewMode]
  );

  //Flashlist causes infinite render loop in v2 for android, reverting to FlatList for now since it's small list should be fine

  return (
    <FlashList
      data={data}
      keyExtractor={keyExtractor}
      horizontal
      snapToInterval={FULL_SIZE + SPACING}
      showsHorizontalScrollIndicator={false}
      decelerationRate="fast"
      renderItem={renderItem}
    />
  );
};

export default memo(StatsList);

Expo Snack or minimal reproduction link:
https://snack.expo.dev/@rtn95/exceeded-max-renders-without-commit

Platform

  • iOS
  • [x ] Android
  • Web (if applicable)

Environment

Only happens in production build and mostly on Oppo Devices.

FlashList version: "@shopify/flash-list": "^2.1.0",
"react-native-gesture-handler": "^2.28.0",

Additional context

The issue disappears when switching back to FlatList. I don't get any why-did-you-render logs when using FlatList and tested a production build which does not crash.
The bug seems tied to layout measurement or prop identity within FlashList’s internal components.
The problem only occurs on specific Android devices.

Checklist

  • [x ] I've searched existing issues and couldn't find a duplicate
  • I've provided a minimal reproduction (Expo Snack preferred)
  • [x ] I'm using the latest version of @shopify/flash-list
  • [x ] I've included all required information above

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions