ScrollView
s 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 ScrollView
s 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
ScrollView
s, i.e. aScrollView
within aScrollView
, 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
callednestedScrollEnabled
but requires Android API level 21+. React Native v0.63 comes with Android API level 24. -
FlatList
inheritsScrollView
props (unless it is nested in anotherFlatList
of the same orientation). To fix my problem therefore, I just needed to add thenestedScrollEnabled
prop to myFlatList
. See the docs for more info.
Let's chat! I'm on Twitter and Instagram @bionicjulia. My website is https://bionicjulia.com
Top comments (0)