Avatar

Nǐ hǎo, I'm Julia.

React Native ScrollView Gotchas

#react-native

4 min read

ScrollViews are one of the basic, most used components in React Native. Here are a couple of common gotchas you might come across when working with nested ScrollViews and how to solve them.

VirtualizedLists error

I was using a FlatList to render a list of items, when I realised this error appearing in my console.

VirtualizedLists should never be nested inside plain ScrollViews with the same orientation - use another VirtualizedList-backed container instead.

First things first, what is a VirtualizedList? According to the docs, a VirtualizedList is a:

Base implementation for the more convenient <FlatList> and <SectionList> components

...which is therefore how it links to the FlatList I was trying to implement.

If you've not come across this component before, FlatList is basically an efficient way of rendering a list of items in your React Native UI. It does this by only rendering the items that appear on screen, compared to ScrollView, which renders all items, even if they appear off-screen.

What the error was trying to tell me, was that somewhere in my component tree lay a parent ScrollView, that was wrapping the FlatList. This is not optimal because wrapping the components in this way means that React Native will no longer be able to figure out the size of the current window in order to render the FlatList effectively.

The way to fix this therefore, was just to remove the ScrollView and transfer the UI contents the ScrollView was rendering into the FlatList component through the ListHeaderComponent and ListFooterComponent props.

<FlatList
  data={data}
  ListHeaderComponent={ContentAboveTheFlatListFromScrollView}
  ListFooterComponent={ContentBelowTheFlatListFromScrollView}
/>

Unfortunately, this was not possible in the code base I was working on because we use ScrollView to render our basic screen template, which is used for all the screens in our app. There was thus, no easy fix for this without doing a complete refactor of our entire app, so the intermediate step I took in the meantime was to hide this error.

The way I did this was in the root component, by adding this snippet of code:

import { LogBox } from 'react-native'

React.useEffect(() => {
  LogBox.ignoreLogs(['VirtualizedLists should never be nested'])
}, [])

At the time of writing this, our code base uses React Native version 0.63.3. LogBox has been switched on by default since version 0.63, and is a redesign of RedBox, YellowBox, and the logging experience in React Native. What I'm effectively doing here is suppressing the warning.

Nested ScrollViews

Extending the situation I have above, I now have this other situation with my component tree:

ScrollView (from our basic screen template), wrapping a MaterialTopTabNavigator (used to render a tabbed view), with each tabbed screen wrapping a FlatList (used to render a list of items within each tabbed screen).

What I was finding what a strange bug whereby the FlatList was rendering as expected in iOS, where users could scroll through the list, but that this was not scrollable in Android.

What I found out in the process of fixing this bug was:

  • When dealing with nested ScrollViews, i.e. a ScrollView within a ScrollView , there's a difference between iOS and Android. iOS automatically enables nested ScrollViews by default (i.e. allows scrolling!), whereas you'll need to manually enable this in Android.
  • This is done through a prop on ScrollView called nestedScrollEnabled but requires Android API level 21+. React Native v0.63 comes with Android API level 24.
  • FlatList inherits ScrollView props (unless it is nested in another FlatList of the same orientation). To fix my problem therefore, I just needed to add the nestedScrollEnabled prop to my FlatList. See the docs for more info.

© 2016-2024 Julia Tan · Powered by Next JS.