Skip to content

VirtualizedLists Nested in ScrollViews

Problem

When working with React Native, you may encounter the warning: "VirtualizedLists should never be nested inside plain ScrollViews with the same orientation because it can break windowing and other functionality." This occurs when you nest components like FlatList or SectionList inside a ScrollView with the same orientation (typically vertical).

The issue arises because both components implement scrolling functionality and virtualization optimizations that conflict when nested. This can lead to performance problems, incorrect scroll behavior, and broken UI interactions.

Solutions

For most use cases, the simplest solution is to disable scrolling on the nested FlatList while keeping it inside the ScrollView:

tsx
<ScrollView>
  {/* Header content */}
  <FlatList
    data={data}
    scrollEnabled={false}
    renderItem={({ item }) => <ListItem item={item} />}
    keyExtractor={(item) => item.id}
  />
  {/* Footer content */}
</ScrollView>

TIP

This approach maintains the performance benefits of FlatList virtualization while preventing scroll conflicts.

Solution 2: Replace FlatList with Map for Small Lists

If your list contains a small number of items (typically less than 10-15), consider using a simple map() instead:

tsx
<ScrollView>
  {/* Header content */}
  {data.map((item, index) => (
    <ListItem key={index} item={item} />
  ))}
  {/* Footer content */}
</ScrollView>

WARNING

Avoid this approach for large lists as it lacks the performance optimizations of virtualized lists.

Instead of nesting in a ScrollView, use the FlatList's built-in header and footer capabilities:

tsx
<FlatList
  data={data}
  renderItem={({ item }) => <ListItem item={item} />}
  keyExtractor={(item) => item.id}
  ListHeaderComponent={
    <>
      {/* Content that would have been above the list */}
    </>
  }
  ListFooterComponent={
    <>
      {/* Content that would have been below the list */}
    </>
  }
/>

Solution 4: Use SectionList for Complex Layouts

For more complex layouts with multiple sections, consider using SectionList:

tsx
<SectionList
  sections={[
    {
      title: 'Header Section',
      data: [],
      renderItem: () => (
        {/* Your header components */}
      )
    },
    {
      title: 'Main Content',
      data: data,
      renderItem: ({ item }) => <ListItem item={item} />
    },
    {
      title: 'Footer Section',
      data: [],
      renderItem: () => (
        {/* Your footer components */}
      )
    }
  ]}
  keyExtractor={(item, index) => index.toString()}
/>

Solution 5: Use Different Orientations

If you need both components to remain scrollable, use different orientations:

tsx
<ScrollView> {/* Vertical by default */}
  {/* Content */}
  <ScrollView horizontal={true}>
    <FlatList
      horizontal={true}
      data={data}
      renderItem={({ item }) => <ListItem item={item} />}
    />
  </ScrollView>
  {/* More content */}
</ScrollView>

Best Practices

  1. Prioritize FlatList with disabled scrolling for most use cases involving medium to large lists
  2. Use simple maps for small lists when performance isn't a concern
  3. Leverage built-in header/footer components when possible for cleaner architecture
  4. Consider SectionList for complex section-based layouts
  5. Avoid suppressing warnings with LogBox.ignoreLogs() as it masks underlying issues

Performance Considerations

  • Virtualized lists (FlatList, SectionList) provide significant performance benefits for large datasets
  • Nesting virtualized lists can negate these optimizations and cause memory issues
  • Always test scroll performance with your actual data size on target devices

By following these approaches, you can resolve the nesting warning while maintaining optimal performance and user experience in your React Native applications.