React-Native another VirtualizedList-backed container

JavascriptReactjsReact Native

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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 - Javascript

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 - Javascript

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 - Javascript

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

Solution 5 - Javascript

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 6 - Javascript

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

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

to:

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

and all those warnings disappeared.

Solution 7 - Javascript

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. What I did is:

 /* 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.

Solution 8 - Javascript

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

Solution 9 - Javascript

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

layout I wanted to achieve is like this, and I wanted to get 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 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.

Solution 10 - Javascript

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>

Solution 11 - Javascript

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

Solution 12 - Javascript

In my opinion i can use map instead of FlatList. But in my case i wan't to show large list. Not using FlatList may cause performance issue. so i used this to suppress warning https://github.com/GeekyAnts/NativeBase/issues/2947#issuecomment-549210509

Solution 13 - Javascript

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

Solution 14 - Javascript

This may help someone down the line, 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.

Solution 15 - Javascript

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>

Solution 16 - Javascript

I was having this issue using a scrollview as parent view, and nesting a SelectBox from 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 still present but scrolling within 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.

Solution 17 - Javascript

Actually as I know, using nested VirtualizedLists, caused always performance issues, just the warning to that issue is new. I tried everything I found on the internet, non of them helped. I use now ScrollView or when you just have a normall View with maxHeight then you will be able to scroll if the content-height is bigger then 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>

Solution 18 - Javascript

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>

Solution 19 - Javascript

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. 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid SchillingView Question on Stackoverflow
Solution 1 - JavascriptAfraz HussainView Answer on Stackoverflow
Solution 2 - JavascriptEdward D'SouzaView Answer on Stackoverflow
Solution 3 - JavascriptNisharg ShahView Answer on Stackoverflow
Solution 4 - JavascriptVishal PawarView Answer on Stackoverflow
Solution 5 - JavascriptTuan Dat TranView Answer on Stackoverflow
Solution 6 - JavascriptVariagView Answer on Stackoverflow
Solution 7 - JavascriptarnaudambroView Answer on Stackoverflow
Solution 8 - JavascriptMike GrantView Answer on Stackoverflow
Solution 9 - JavascriptTakahiro NishinoView Answer on Stackoverflow
Solution 10 - Javascriptgaurav gandhiView Answer on Stackoverflow
Solution 11 - JavascriptsaqibView Answer on Stackoverflow
Solution 12 - JavascripttvankithView Answer on Stackoverflow
Solution 13 - Javascriptazwar_akbarView Answer on Stackoverflow
Solution 14 - JavascriptAvrahm KleinholzView Answer on Stackoverflow
Solution 15 - Javascriptgianlop3zView Answer on Stackoverflow
Solution 16 - JavascriptAnassView Answer on Stackoverflow
Solution 17 - JavascriptMaziar B.View Answer on Stackoverflow
Solution 18 - JavascriptSagittariusView Answer on Stackoverflow
Solution 19 - JavascriptSyed MulthazimView Answer on Stackoverflow