215

After upgrading to React Native 0.61, I get a lot of warnings like this:

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

What is the other VirtualizedList-backed container that I should use, and why is it now advised not to use it like that?

4
  • 2
    Could you entitle your question the full warning message ? because it is not so easy to find with your current title. Commented Oct 15, 2020 at 10:58
  • 9
    Just for anyone who might have the same problem as me, it was because i encapsulated a <FlatList /> inside a <ScrollView /> Commented Jan 19, 2021 at 7:40
  • In case of not having more items in FlatList, just render items inside of ScrollView and not use FlatList Commented Nov 6, 2021 at 6:23
  • 1
    If you have horizontal={false} (=>vertical) for FlatList insideScrollView, just replace the ScrollView with regular View (if you have more content besides FlatList). Don't have any other paralel content in the wrapping view? => simply don't wrap the FlatList in the ScrollView at all ;-) (SafeAreaView is iOS only)
    – jave.web
    Commented Mar 14, 2022 at 2:36

28 Answers 28

171

If someone's still looking for a suggestion to the problem that Ponleu and David Schilling have described here (regarding content that goes above the FlatList), then this is the approach I took:

<SafeAreaView style={{flex: 1}}>
    <FlatList
      data={data}
      ListHeaderComponent={ContentThatGoesAboveTheFlatList}
      ListFooterComponent={ContentThatGoesBelowTheFlatList} />
</SafeAreaView>

You can read more about this in ListHeaderComponent.

10
  • 2
    Do you know why this should be better then the way the warning gets produced? Commented Nov 13, 2019 at 7:06
  • 9
    @DavidSchilling because the way you tried results with 2 scroll containers: ScrollView and FlatList - you'll get inconsistent scroll behaviour. Way presented in this answer results in only 1 scroll container and in Header/Footer you can put any view, no matter how complex.
    – Variag
    Commented Nov 14, 2019 at 8:33
  • 1
    @Ponleu You can memoize your ContentThatGoesAboveTheFlatList component by using the useMemo hook provided by React, to avoid re-renders. More information here: reactjs.org/docs/hooks-reference.html#usememo Let me if it’s helpful. :) Commented Nov 23, 2019 at 6:09
  • 6
    I need two flat lists with different data sets in one page... what should i do? Commented Oct 22, 2020 at 12:01
  • 1
    @AtharRajpoot this method still works for that just have the ListFooterComponent be the FlatList of the second data set. If you want a header for the second data set, just wrap it in a fragment with the flatlist
    – Ryker
    Commented Jun 7, 2021 at 16:31
78

Just in case this helps someone, this is how I fixed the error in my case.

I had a FlatList nested inside a ScrollView:

render() {
    return (
        <ScrollView>
            <Text>{'My Title'}</Text>
            <FlatList
                data={this.state.myData}
                renderItem={({ item }) => {
                    return <p>{item.name}</p>;
                }}
            />
            {this.state.loading && <Text>{'Loading...'}</Text>}
        </ScrollView>
    );
}

and I got rid of the ScrollView by using the FlatList to render everything I needed, which got rid of the warning:

render() {
    const getHeader = () => {
        return <Text>{'My Title'}</Text>;
    };

    const getFooter = () => {
        if (this.state.loading) {
            return null;
        }
        return <Text>{'Loading...'}</Text>;
    };

    return (
        <FlatList
            data={this.state.myData}
            renderItem={({ item }) => {
                return <p>{item.name}</p>;
            }}
            ListHeaderComponent={getHeader}
            ListFooterComponent={getFooter}
        />
    );
}
1
  • 7
    To whoever is looking for the best answer: "Go for this one. Use only one FlatList."
    – cmcodes
    Commented Jun 15, 2020 at 14:14
58

The best way is to disable that warning, because sometimes Flatlist need to be in ScrollView.

Update React Native v0.63 above

YellowBox is now changed and replaced with LogBox.

Functional

import React, { useEffect } from 'react';
import { LogBox } from 'react-native';

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

Class based

import React from 'react';
import { LogBox } from 'react-native';

componentDidMount() {
    LogBox.ignoreLogs(['VirtualizedLists should never be nested']);
}

Update React Native v0.63 below

Functional

import React, { useEffect } from 'react';
import { YellowBox } from 'react-native';

useEffect(() => {
    YellowBox.ignoreWarnings(['VirtualizedLists should never be nested']);
}, [])

Class based

import React from 'react';
import { YellowBox } from 'react-native';

componentDidMount() {
    YellowBox.ignoreWarnings(['VirtualizedLists should never be nested']);
}
13
  • 27
    You know, warnings are there for a reason, you shouldn't just ignore them... Commented Dec 3, 2020 at 13:29
  • 6
    @RafaelTavares, So why these ignored functions exist at all?
    – Mohsen Zia
    Commented Jan 2, 2021 at 9:40
  • 2
    This doesn't work with react native 0.66 Commented Oct 29, 2021 at 16:29
  • 3
    @DrorBar yes, it became an error starting from RN 0.65. Anyway, you should be aware that when a FlatList is used inside a ScrollView, it fails to detect the screen size and thus cannot virtualize the items that should be 'off screen' rendering all of them immediately, which makes it even less performant than a regular map function, since it still has to create a view and add some logic. that's the reason the warning exists.
    – AlexanderD
    Commented Jan 19, 2022 at 9:15
  • 2
    This really should be the acceptable answer because. The reality is, I am using a component library, where adding a flat list for performance is more ideal that managing the state of an already existing bottomsheet component that is wrapped in a scrollview. Everything functions fine. And this error is truly not valuable to the structure of the views. You can edit the scrollview props if need in the parent to do nothing (thus a regular view if you want it to be). So this is correct and the right answer for sure.
    – thekevshow
    Commented Dec 14, 2022 at 3:35
47

Data

// Dummy data array
const data = [
    {id: 1, name: 'Tom'},
    {id: 2, name: 'Jerry'},
]

Solution #1

You can make a custom component for that like this:

const VirtualizedList = ({children}) => {
    return (
        <FlatList
            data={[]}
            keyExtractor={() => "key"}
            renderItem={null}
            ListHeaderComponent={
                <>{children}</>
            }
        />
    )
}

Then use this VirtualizedList as the parent component:

...
return (
    <VirtualizedList>
         <FlatList
           data={data}
           keyExtractor={(item, index) => item.id + index.toString()}
           renderItem={_renderItem}
         />
         <AnyComponent/>
    </VirtualizedList>
)

Solution #2

If you use FlatList inside the ScrollView, it gives a warning which is annoying, so you can use the array's map property, like this:

Note*: It is not recommended way to show list. If you have a small amount of that, then you can use it that's totally fine, but if you want to show a list which get data from an API and have lots of data, then you can go with other solutions. If you use a map with large data, then it affects your app's performance.

<ScrollView>
    {data.map((item, index) => (
        <View key={index}>
           <Text>{item.name}</Text>
        </View>
    ))}
</ScrollView>

Solution #3

If you make your FlatList horizontal (as per your need) then also the warning will disappear:

<ScrollView>
    <FlatList
       data={data}
       keyExtractor={(item, index) => item.id + index.toString()}
       horizontal={true}
    />
</ScrollView>

Solution #4

You can add a header and footer component.

In ListHeaderComponent and ListFooterComponent, you can add any component, so you don't need the parent ScrollView.

<FlatList
   data={data}
   keyExtractor={(item, index) => item.id + index.toString()}
   ListHeaderComponent={headerComponent}
   ListFooterComponent={footerComponent}
   ListEmptyComponent={emptyComponent}
   ItemSeparatorComponent={separator}
/>

// List components
const headerComponent = () => (
    <View>
       <Header/>
       <Any/>
    </View>
)
const footerComponent = () => (
    <View>
       <Footer/>
       <Any/>
    </View>
)
const emptyComponent = () => (
    <View>
       <EmptyView/>
       <Any/>
    </View>
)
const separator = () => (
    <View style={{height: 0.8, width: '100%', backgroundColor: '#fff'}} />
)
9
  • 5
    FlatList is usually used to dynamically load and show data. Converting it to a static list is not an approach in most cases. Commented Nov 25, 2020 at 7:30
  • It work's perfectly, may be you did some mistake. Commented Apr 11, 2021 at 18:25
  • 1
    in my case horizontal={false} did the trick, coz horizontal={true} will lead FlatList to render items horizontally, which nobody wants...
    – NBaua
    Commented May 10, 2021 at 3:24
  • As I said above, set it horizontal={true} as per your requirement. Commented May 13, 2021 at 11:11
  • 1
    Solution #5: patch-package Commented Jul 27, 2022 at 17:40
19

After React Native 0.71, if you have prop scrollEnabled={false} in the FlatList, the error should not show anymore, as changelog:

Added a check to if scrollEnabled is not false, if so then fire the VirtualizedList error

1
  • Funcionou para mim Commented Oct 11, 2023 at 22:50
16

The warning appears, because ScrollView and FlatList share the same logic. If FlatList runs inside ScrollView, it's duplicated.

By the way, SafeAreaView doesn't work for me. The only way to solve it is:

<ScrollView>
    {data.map((item, index) => {
        ...your code
    }}
</ScrollView>

The error disappears.

5
  • This one worked for me. I needed Flatlist inside Scrollview and the good old map function you have suggested here did it for me!
    – Muteshi
    Commented Oct 27, 2020 at 18:20
  • 1
    Don't understand this. How does the map help? Where did the FlatList go?
    – Ken
    Commented Feb 15, 2021 at 15:24
  • Idea is correct, but code not working. Commented Nov 12, 2021 at 22:15
  • 1
    Don't do it! FlatList provide lazy loading (if the content is not inside the screen it won't be rendered). Array.map() method don't, i don't recommend this if you will handle big data list.
    – gianlop3z
    Commented Feb 14, 2022 at 2:31
  • if you look for performance don't use map )
    – Hamed
    Commented Mar 8, 2022 at 12:14
13

The below code works perfectly for me to disable the annoying error:

VirtualizedLists should never be nested inside plain ScrollViews with the same orientation, because it can break windowing and other functionality. Use another VirtualizedList-backed container instead.

React Native 0.68.2:

  <ScrollView horizontal={false} style={{flex: 1}}>
    <ScrollView
      horizontal={true}
      contentContainerStyle={{width: '100%', height: '100%'}}>
      <FlatList ... />
    </ScrollView>
  </ScrollView>
1
  • 1
    This removes the error but there is no Flatlist scroll. In my case it still works well because I'm only displaying a couple data results.
    – Cory
    Commented Apr 28, 2023 at 17:21
9

Looking at the examples in the documentation, I've changed the container from:

<ScrollView>
    <FlatList ... />
</ScrollView>

to:

<SafeAreaView style={{flex: 1}}>
    <FlatList ... />
</SafeAreaView>

And all those warnings disappeared.

6
  • 18
    What if I render content above FlatList insides ScrollView and want that content to be scrollable?
    – Ponleu
    Commented Oct 9, 2019 at 4:44
  • 2
    It isn't good user experience to have two scrollable views one next to another. I would try to nest it like this: '<View><ScrollView><Content /></ScrollView><FlatList ... /></View>' (not tested)
    – Variag
    Commented Oct 9, 2019 at 5:03
  • 1
    I'm pretty sure FlatList will not create another scroll, unless we wrap it in aside a container with specified height.
    – Ponleu
    Commented Oct 9, 2019 at 9:13
  • 1
    i have the same problem as @Ponleu. I have a ScrollView inside of that some content and then a FlatList also inside the ScrollView. And i want the whole screen to scroll together. Commented Oct 10, 2019 at 15:08
  • 10
    The main point of the ScrollView was to make it scrollable vertically for example. Taking that property won't leave it scrollable again. What was the point here? Commented Mar 7, 2020 at 9:51
6

In my case, I needed to have FlatLists nested in a ScrollView, because I am using react-native-draggable-flatlist to move ingredients and steps around in a recipe.

If we read the warning properly, it says that we should use another VirtualizedList-backed container to nest our child FlatList in.

I did:

/* Outside the component */
const emptyArry = []

/* Render */
<FlatList
    scrollEnabled={false}
    horizontal
    data={emptyArray}
    ListEmptyComponent=(<DraggableList />)
/>

No more warning, and I think this is the pattern recommended by the warning.

5
<ScrollView horizontal={false} style={{width: '100%', height: '100%'}}>
   <ScrollView horizontal={true} style={{width: '100%', height: '100%'}}>
      <FlatList ... />
   </ScrollView>
</ScrollView>
4

You have to remove ScrollView and enable scroll from FlatList using the property scrollEnabled={true}, you can place the other views inside ListHeaderComponent and ListFooterComponent

<View flex={1}>
  <FlatList 
    data={data}
    scrollEnabled={true}
    showsVerticalScrollIndicator={false}
    renderItem={({ item }) => (
      <Text>{item.label}</Text>
    )}
    keyExtractor={item => item.id}
    ListHeaderComponent={() => (
        <Text>Title</Text>
    )}
    ListFooterComponent={() => (
        <Text>Footer</Text>
    )}
  />
</View>
3

I tried some ways to solve this, including ListHeaderComponent or ListFooterComponent, but it all didn't fit for me.

The layout I wanted to achieve is like this, and I wanted to get it scrolled in once.

<ScrollView>
  <View>I'm the first view</View>
  <View>I'm the second view</View>
  <MyFlatList />
</ScrollView>

First, I want to say thanks to this issue and comments, which gave me a bunch of ideas.

I was thinking of ListHeaderComponent places above the Flatlist, but since my Flatlist's direction was column, the header I wanted to place went on the left of the Flatlist :(

Then I had to try on VirtualizedList-backed thing. I just tried to pack all components in VirtualizedList, where renderItems gives index and there I could pass components conditionally to renderItems.

I could have worked this with Flatlist, but I haven't tried yet. Finally, it looks like this.

<View>
  <Virtualizedlist
    data={[]}
    initialNumToRender={1}
    renderItem={(props)=>{
      props.index===0 ? (1st view here) : props.index===1 ? (2nd view here) : (my flatlist)
    }}
    keyExtractor={item => item.key}
    getItemCount={2}
    getItem={ (data, index) => {
      return {
        id: Math.random().toString(12).substring(0),
      }
    }}
  />
</View>

(inside which lazyly renders↓)
  <View>I'm the first view</View>
  <View>I'm the second view</View>
  <MyFlatList />

And of course able to scroll the whole screen.

3

As Brahim stated, setting the horizontal property to true seem to resolve the issues for a FlatList embedded in a ScrollView.

3
  • 5
    I don't know why so many people mention the horizontal property solutions, this breaks completely my design, I'm sure others as well
    – Rolando
    Commented Nov 1, 2021 at 15:29
  • If numColumns property is used then horizontal property breaks it at all.
    – Kh An
    Commented Dec 4, 2021 at 17:23
  • Yes, it so strange why guys is recommending this way with horizontal={true}, because it changes orientation of the scroll
    – jocoders
    Commented Jan 21, 2022 at 9:32
2

I was having this issue using a scrollview as the parent view, and nesting a SelectBox from the react-native-multi-selectbox package.

I was able to solve this by adding listOptionProps={{nestedScrollEnabled: true}} like this:

<ScrollView>
  <SelectBox
    label="Select single"
    options={serverData}
    listOptionProps={{nestedScrollEnabled: true}}
    value={input.elementSelected}
    onChange={event =>
      inputHandlerLang('elementSelected', event, key)
    }
    hideInputFilter={false}
  />
</ScrollView>

The error is still present, but scrolling within a SelectBox works as well as within the parent scrollview. I also do have to suppress the error with LogBox. I don't know if there are any drawbacks to this, but I'll try to test this more.

This used to work in v0.68.2, but since I updated to patch v0.68.5, the warning became an error.

1

So I faced the same problem while using a picker-based component inside <ScrollView> and the one thing that helped me solve the problem was adding keyboardShouldPersistTaps={true} inside the <ScrollView> as a prop.

This is my code snippet.

<ScrollView keyboardShouldPersistTaps={true}> 
      <SelectionDD studentstatus={studentStatus}/>
      <SearchableDD collegeNames={collegeNames} placeholder='University'/>
</ScrollView>
3
  • 2
    it deprecated .. must be keyboardShouldPersistTaps="always"
    – cantaş
    Commented Aug 13, 2020 at 6:11
  • I am not sure if it has recently changed. But thanks a lot for the information!! Commented Aug 31, 2020 at 20:30
  • 1
    This doesn't remove the error for me
    – velkoon
    Commented Jun 1, 2022 at 17:54
1

I have two Flatlist; each of them has many Item also has a feature to collapse and expand. Because of that, I can't use SafeAreaView.

I saw another solution and found a new way.

I define one Flatlist in the core component ( without Scrollview) and render each Flatlist with a map function inside ListHeaderComponent and ListFooterComponent.

 <View style={{flex: 1}}>
    <FlatList
        style={{backgroundColor: 'white'}}
        refreshing={loading}
        onRefresh={() => sample()}
        ListHeaderComponent = {
          <View>
             {collapse/expandComponent}
             {this.state.sample1&& content1.map((item, index) => this.renderList1(item,index))}
          </View>
        }
        ListFooterComponent = {
          <View>
            {collapse/expandComponent}
            {this.state.sample2 && content2.map((item, index) => this.renderlist2(item,index))}
          </View>
        }
      />
  </View>
0

Use flatList like this ListHeaderComponent and ListFooterComponent:

<FlatList ListHeaderComponent={
    <ScrollView
        style={styles.yourstyle}
        showsVerticalScrollIndicator={false}
    >
        <View style={styles.yourstyle}>
        </View>
    </ScrollView>
    }
    data={this.state.images}
    renderItem={({ item, index }) => {
        return (
            <View
                style={styles.yourstyle}
            >
                <Image
                    source={{
                        uri: item,
                    }}
                    style={styles.yourstyle}
                    resizeMode={"contain"}
                />
                <Text
                    numberOfLines={2}
                    ellipsizeMode="tail"
                    style={styles.yourstyle}
                >
                    {item.name}
                </Text>
            </View>
        );
    }}
    keyExtractor={({ name }, index) => index.toString()}
    ListFooterComponent={
        <View style={styles.yourstyle}></View>
    }
/>
0

If you use ScrollView and FlatList together you'll get inconsistent scroll behaviour. So just remove ScrollView and use FlatList in a View.

<View flex={1}>
<FlatList 
    data={list}
    renderItem={({ item }) => this.renderItem(item) }
    keyExtractor={item => item.id}
    />
</View>
0
import React from 'react';
import { FlatList, ScrollViewProps } from 'react-native';

export const ScrollView: React.FC<ScrollViewProps> = props => {
  return (
    <FlatList
      {...props}
      data={[]}
      renderItem={() => null}
      ListHeaderComponent={() => (
        <React.Fragment>{props.children}</React.Fragment>
      )}
      ListEmptyComponent={null}
      keyExtractor={() => 'blank'}
    />
  );
};

This will essentially work exactly like a ScrollView except without this error.

0

A lot of things here did not work for me. That isn't to say that solutions are broken or wrong. Some look similar to the React Native docs examples.

So to avoid headaches, one thing I have just come to terms with (and I was building my app, so you might not have room to do this), is that if you just make the FlatList horizontal (using the horizontal boolean property), you avoid all of the experimenting. Vertical flat lists in vertical views seem to have a conflict.

Making the flat list horizontal was a quick and painless way for me to keep things moving forward. No one would use the UI (most likely, and especially with all options in full view) and think to themselves, this app would be great if this list of touchable items was vertical instead.

Just leaving this for those few people who could live with just making it horizontal and moving on in 20 seconds instead of wasting 40 minutes trying to work different solutions around this.

1
0

Without hiding YellowBox, you still can implement a scrollable view inside a scrollable view. You can use this library. It replaces the default Scrollview from React Native.

0

Be sure you to check how your components are nested. Removing the ScrollView from the top component fixed the issue.

I ran into this issue, because I had two components nested like this essentially:

Component 1

<ScrollView>
   <OtherStuff />

   <ListComponent />
</ScrollView>

My second component 'ListComponent' had a FlatList already wrapped with SafeAreaView.

<SafeAreaView style={styles.container}>
    <FlatList
        data={todoData}
        renderItem={renderItem}
        ItemSeparatorComponent={() => <View style={styles.separator} />}
        keyExtractor={item => item.id.toString()}
    />
</SafeAreaView>

In the end, I replaced the ScrollView from the first component with a View instead.

-1

This error disappeared because of using FlatList inside ScrollView. You can write like the following code.

<SafeAreaView style={styles.container}>
            <View style={styles.container}>
              <View>
                <Header />
              </View>

                {(list.length == 0) &&
                  <View style={{flex:1, margin: 15}}>
                    <Text style={{textAlign: 'center'}}>No peripherals</Text>
                  </View>
                }
                <FlatList 
                  data={list}
                  renderItem={({ item }) => this.renderItem(item) }
                  keyExtractor={item => item.id}
                />
            </View>
          </SafeAreaView>
-1

You can add horizontal=True and contentContainerStyle={{ width: '100%' }} to the ScrollView parent.

<ScrollView
  style={styles.collaborators}
  contentContainerStyle={{ width: '100%' }} <-- 
  horizontal <--
>
  <FlatList
    data={list?.slice(0, 10) || []}
    keyExtractor={item => item.cc}
    ItemSeparatorComponent={Separator}
    renderItem={({ item }) => (
      <Collaborator name={item.name} cc={item.cc} />
    )}
  />
</ScrollView>
1
  • using this won't let me scroll Commented Jun 2, 2022 at 6:57
-1

This worked for me (as a bit of a hack). Use a FlatList with empty data and null renderItem props instead of using a ScrollView

const emptyData = [];

const renderNullItem = () => null;

const App = () => {
  const ListFooterComponent = (
    <FlatList ... />
  );

  return (
    <SafeAreaView>
      <FlatList
        data={emptyData}
        renderItem={renderNullItem}
        ListFooterComponent={ListFooterComponent}
      />
    </SafeAreaView>
  );
};
1
  • 1
    Why would you do that? If you do not use flatList then just use ScrollView Commented Dec 30, 2022 at 13:07
-1

In my opinion, I can use map instead of FlatList. But in my case I CPU to show large list. Not using FlatList may cause performance issue. So I used this to suppress the warning: Nested VirtualizedLists Warning in Flatlist with Tags #2947

-1

Actually, as I know, using nested VirtualizedLists, always causes performance issues, just the warning to that issue is new.

I tried everything I found on the Internet, but none of them helped. I use now ScrollView or when you just have a normal View with maxHeight, then you will be able to scroll if the content-height is bigger than the maxHeight of you View.

So:

<ScrollView>
   {items.map((item, index) =>
       <YourComponent key={index} item={item} />
   )}
</ScrollView>

Or just:

<View style={{maxHeight: MAX_HEIGHT}}>
    {items.map((item, index) =>
       <YourComponent key={index} item={item} />
    )}
</View>
1
  • 4
    FlatList is usually used to dynamically load and show data. Converting it to a static list is not an approach in most cases. Commented Nov 25, 2020 at 7:31
-6

I had the same issue, and just got rid of it by removing the ScrollView around the FlatList. Because by default FlatList provides Scroll Functionality based on the length of content that it renders. 😊

1
  • 1
    This won't work if you have other content/components that are siblings to the FlatList on the same screen.
    – Case Silva
    Commented Sep 17, 2020 at 19:25

Not the answer you're looking for? Browse other questions tagged or ask your own question.