React-Native another VirtualizedList-backed container

After upgrading to react-native 0.61 i get a lot of warnings like that:

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 like that?


Solution 1:

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 here: https://facebook.github.io/react-native/docs/flatlist#listheadercomponent

Hopefully it helps someone. :)

Solution 2:

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}
        />
    );
}

Solution 3:

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

UPDATE RN V0.63 ABOVE

YellowBox is now changed and replace 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 RN 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']);
}

Solution 4:

The warning appears because ScrollView and FlatList share the same logic, if FlatList run inside ScrollView, it's duplicated

By the way SafeAreaView doesn't work for me, the only way to solve is

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

The error disappears

Solution 5:

Solution #1

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

You can also 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 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 warning which is annoying, so you can use array's map property, like this -

<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 warning will disappear

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

Solution #4

you can add header and footer component

In ListHeaderComponent and ListFooterComponent you can add any component so you don't need 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'}} />
)