Nested FlatList's onViewableItemsChanged fires for rows that are only mounted, not actually on-screen, when nested inside another FlatList's row
When a FlatList is nested inside an item rendered by another FlatList (for example, a vertical list of sections where each section contains a horizontal carousel), the inner FlatList's onViewableItemsChanged callback reports items as viewable immediately after the child list mounts. This happens even when the parent FlatList has rendered the row only as part of its render-ahead buffer, before the row has actually entered the viewport. As a result, onViewableItemsChanged fires for child items that are not yet visible on the screen, leading to false-positive impression or analytics events.
Environment
- react-native: 0.79.6
- react: 19.0.0
- expo: ^53.0.27
- Platform: Android (physical device)
*Code Implementation
*
const viewabilityConfig = {
itemVisiblePercentThreshold: 30,
};
const onParentViewableItemsChanged = ({ viewableItems }) => {
console.log(
"Parent:",
viewableItems.map(v => v.item.id)
);
};
const onChildViewableItemsChanged = ({ viewableItems }) => {
console.log(
"Child:",
viewableItems.map(v => v.item.id)
);
};
function ChildList() {
return (
horizontal
data={childData}
renderItem={({ item }) => }
onViewableItemsChanged={onChildViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
/>
);
}
export default function App() {
return (
data={sections}
renderItem={() => (
Section
)}
onViewableItemsChanged={onParentViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
/>
);
}
Is this the expected behavior of VirtualizedList? Since the child FlatList is mounted while the parent row is still in the render-ahead buffer, should onViewableItemsChanged be deferred until the child itself intersects the viewport? If not, is there a recommended way to prevent premature child viewability callbacks without introducing additional visibility state or conditional rendering? I'm looking for a solution that doesn't add noticeable runtime overhead.
Top comments (0)