VirtualizedLists should never be nested inside plain ScrollViews with the same orientation - react-native

I'm building a mobile application with React Native, and I have a ScrollView inside one of the pages.
The problem is that I have in this page a FlatList so when I go to that page, I get this error:
VirtualizedLists should never be nested inside plain ScrollViews with the same orientation... The thing is, I set the ScrollView nestedScrollEnabled to true and I also set the FlatList's scrollEnabled to false because I don't really need the scroll there (I'm using it to render items from an enum) so I thought that should fix the error, but the error still persist.
It looks like this:
<ScrollView showsVerticalScrollIndicator={false} nestedScrollEnabled={true}>
<MyComponent />
</ScrollView>
And MyComponent has this FlatList:
<FlatList
scrollEnabled={false}
style={{padding: 8,marginBottom: 8,}}
data={categories}
numColumns={numOfColumns}
keyExtractor={category => category}
renderItem={item => renderItem(item.item)}
/>
It essentially looks like this:
<SafeAreaView>
<ScrollView>
<FlatList />
<OTHER COMPONENTS />
</ScrollView>
</SafeAreaView>

Your component FlatList and ScrollView have the same orientation(vertical), so you need put your component inside a ScrollView with horizontal orientation like this:
<View>
<ScrollView nestedScrollEnabled={true} style={{ width: "100%" }} >
<View>
<ScrollView horizontal={true} style={{ width: "100%" }}>
<MyComponent />
</ScrollView>
</View>
</ScrollView>
</View>

The error is because you are using a FlatList inside a ScrollView.
The FlatList is already a scrollable component,
FlatList are accepting props like ListHeaderComponent for rendering header content and ListFooterComponent for rendering footer content. Here you can remove the ScrollView and instead of that you can only render FlatList for making whole page scrollable
You need to change your code as shown below:
const _renderHeader = () => <Text>Your Header</Text>
const _renderFooter = () => <Text>Your Footer</Text>
const _renderFooter = () => <Text>FlatList items</Text>
<SafeAreaView>
<FlatList
data={data}
keyExtractor={(item, index) => String(index)}
renderItem={_renderItem}
ListHeaderComponent={_renderHeader}
ListFooterComponent={_renderFooter}
ListFooterComponentStyle={styles.footerStyle} //If you need to give specific styles for footer component
ListHeaderComponentStyle={styles.headerStyle} //for header comp style
/>
</SafeAreaView>
You don't want to use a ScrollView when you are using a FlatList
You can check the official docs for more clarification

Related

Aligning ListHeaderComponent vertically above Horizontal Flatlist

I have a horizontal Flatlist and right above it i want to add a custom header. I have an option to wrap the Flatlist & custom header in a ScrollView - which isn't good practice according to RN 0.61
VirtualizedLists should never be nested inside plain ScrollViews with
the same orientation
Another option is to use:
ListHeaderComponent
<FlatList
horizontal
ListHeaderComponent = {<CustomHeader>What can we help you find?</CustomHeader> }
keyExtractor = {(item) => item.unique_id }
data = {this.props.categories}
contentContainerStyle={{ flexGrow: 1}}
renderItem={ ({item}) => (
<TouchableOpacity>
<View>
<Image
style={{
height:80,
width:100}}
source={{uri:'some_url'}}
/>
<Title>{item.category}</Title>
</View>
</TouchableOpacity>)}
/>
Whilst the above works with a vertical Flatlist, it completely fails with a horizontal flatlist with my use case.
Expected:
Actual Output:
What are the possible fixes?
You can Conditional Rendering like this, just a workaround
{this.props.category.length ? <CustomHeader>What can we help you find?</CustomHeader> : null}
<FlatList
horizontal
keyExtractor = {(item) => item.unique_id }
data = {this.props.categories}
contentContainerStyle={{ flexGrow: 1}}
renderItem={ ({item}) => (
<TouchableOpacity>
<View>
<Image
style={{
height:80,
width:100}}
source={{uri:'some_url'}}
/>
<Title>{item.category}</Title>
</View>
</TouchableOpacity>)}
/>

VirtualizedLists should never be nested error

I'm building a mobile application with React Native, and I have a ScrollView inside one of the pages.
The problem is that I have in this page a FlatList so when I go to that page, I get this error:
VirtualizedLists should never be nested inside plain ScroolViews with the same orientation... The thing is, I set the ScrollView nestedScrollEnabled to true and I also set the FlatList's scrollEnabled to false because I don't really need the scroll there (I'm using it to render items from an enum) so I thought that should fix the error, but the error still persist.
It looks like this:
<ScrollView showsVerticalScrollIndicator={false} nestedScrollEnabled={true}>
<MyComponent />
</ScrollView>
And MyComponent has this FlatList:
<FlatList
scrollEnabled={false}
style={{padding: 8,marginBottom: 8,}}
data={categories}
numColumns={numOfColumns}
keyExtractor={category => category}
renderItem={item => renderItem(item.item)}
/>
Can you try to add the property nestedScrollEnabled={true} to both the parents and the children:
<ScrollView showsVerticalScrollIndicator={false} nestedScrollEnabled={true}>
<MyComponent />
</ScrollView>
<FlatList
nestedScrollEnabled={true}
scrollEnabled={false}
style={{padding: 8,marginBottom: 8,}}
data={categories}
numColumns={numOfColumns}
keyExtractor={category => category}
renderItem={item => renderItem(item.item)}
/>
You can use the ListHeaderComponent and ListFooterComponent of the FlatList to render the other parts inside the scrollView. Using a FlatList inside a scrollview limits the performance of the FlatList.
<FlatList
ListHeaderComponent={
<>
<AboveFlatList />
</>
}
data={yourData}
renderItem={this.renderComponents}
...
...
ListFooterComponent={
<>
<BelowFlatList />
</>
}
/>

ERROR - VirtualizedLists should never be nested inside plain ScrollViews with the same orientation

I'm working on a react-native app and I have to put a list of object in a Scrollview, so I use the FlatList component to do it. This is the piece of code that generates the error:
<ScrollView contentContainerStyle={style}>
Other components
<FlatList
style={style}
data={data}
scrollEnabled={false}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index}) => (somethings)}
/>
Other components
</ScrollView>
The complete error is: 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.
Avoid using FlatList with the same orientation. Instead, restructure your code like this --
<ScrollView contentContainerStyle={style}>
Other components
{
data.map((item)=> <Somthing item={item}/>)
}
Other components
</ScrollView>
Flatlist has its own ScrollView you can scroll through the list using that so there is no need to put a flatlist into a ScrollView that is why its giving a warning, the both scrollview will clash and one of them (mostly the parent one) works.
The error is self explanatory and it should be in a developers best interest to avoid these kind of things even when it's just a false alarm.
Your particular situation could use the following solution:
<FlatList
data={data}
keyExtractor={(item, index) => `key-${index}`}
ListHeaderComponent={() => (
<SomeComponents>
...Some components those need to be on top of the list
</SomeComponents>
)}
ListFooterComponent={() => (
<SomeComponents>
...Some components those need to be below the list
</SomeComponents>
)}
renderItem={({ item, index}) => (somethings)}
/>
Another note, if you need more complex list that needs header and footer for the list itself, you can try SectionList.
Your component FlatList and ScrollView have the same orientation(vertical), so you need put your component inside a ScrollView with horizontal orientation like this:
<View>
<ScrollView nestedScrollEnabled={true} style={{ width: "100%" }} >
<View>
<ScrollView horizontal={true} style={{ width: "100%" }}>
<FlatList />
</ScrollView>
</View>
</ScrollView>
</View>
Solution 1: Use FlatList props ListHeaderComponent and create all of your page top section in that. Something like this:
This will not show any warning or error.
Solution 2:
Because only parent view will scroll (ScrollView) and not the child FlatList, so to get rid of the warning you can pass a prop scrollEnabled={false} to the FlatList.
If it doesn't go then import LogBox from react-native and write this in your component
useEffect(() => {
LogBox.ignoreLogs(["VirtualizedLists should never be nested"])
}, [])
hopefully, the warning will be removed.
Anyone want to solve this issue can use a custom VirtualizedScrollView like this:
import React from 'react';
import { FlatList } from 'react-native';
const VirtualizedScrollView = props => {
return (
<FlatList
{...props}
data={[]}
keyExtractor={(e, i) => 'dom' + i.toString()}
ListEmptyComponent={null}
renderItem={null}
ListHeaderComponent={() => (
<>{props.children}</>
)}
/>
);
};
export default VirtualizedScrollView;
Then if you use FlatList inside VirtualizedScrollView, it won't get the warning/error.
<VirtualizedScrollView>
<FlatList
/*--- your props ---*/
/>
</VirtualizedScrollView>
There is a npm package where I get this code, you can also use this package
Solution:
I have also encountered same problem with FlatList. Then the package below solved my problem.
'react-native-virtualized-view'
import { ScrollView } from 'react-native-virtualized-view'
if ScrollView is Vertical change Flatlist Horizontal
<ScrollView >
<FlatList
horizontal
data={lenders}
keyExtractor={(_, index) => index}
renderItem={(item) => {
return <Text>item</Text>
}}
/>
You can solve the 2 vertical ones(I'm assuming their side by side, separated with a segemented control?) by using the same flat list and switching out the data when it's switched. If they're just two vertical flat list's one after another use the SectionList.
For the horizontal one you can try putting the Horizontal FlatList in the ListHeaderComponent of the vertical FlatList and see what happens. It can be janky if you use a vertical FlatList in a vertical scroll view but maybe with two different axis it might be ok. The other option is two only show a few items in the horizontal scrollview and have a "Show More".
The last option is too re design/rethink the page so it's not doing so much. On mobile less is more and developers/designers like to get in the mindset of porting desktop thinking onto mobile. Might be worth a shot.
I used the SectionList approach to solve this & wanted to post a code example because I found the Section data required by React Native to be clear but also quite prescriptive.
renderList = ({empty, posts}: {empty: boolean, posts: Array<Object>}) => (
<SectionList
sections={[
{type: 'MAP', data: [{}]}, // Static sections.
{type: 'PROFILE', data: [{}]},
{type: 'POSTS', data: posts} // Dynamic section data replaces the FlatList.
]}
keyExtractor={(item, index) => index}
renderItem={({item, section}) => {
switch (section.type) {
// Different components for each section type.
case 'MAP':
return <MapView />;
case 'PROFILE':
return <Profile />;
case 'POSTS':
return <Post item={item} />;
default:
return null;
}
}}
ItemSeparatorComponent={() => <Separator />}
ListFooterComponent={() => <>{empty && <EmptyList />}</>}
/>
);
What's nice is that the content feels logically quite separate, so you can add sections easily or have different dynamic data sources.
(If you're building a form & want better keyboard handling, you could also try a KeyboardAwareSectionList from react-native-keyboard-aware-scroll-view.)
Flatlist has an integrated scrollview itself, so you can resolve this error by removing ScrollView Component, And let just the Fatlist component
Error ? you are trying to render a FlatList component inside a scrollview component, this is what is throwing the warning.
solution Render the components using Flatlist's ListHeaderComponent={} prop, i.e in your flatlist add the prop as follows
const FlatList_Header = () => {
return (
<View style={{
height: 45,
width: "100%",
backgroundColor: "#00B8D4",
justifyContent: 'center',
alignItems: 'center'
}}
>
<Text style={{ fontSize: 24, color: 'white' }}> Sample FlatList Header </Text>
</View>
);
}
<FlatList
data={BirdsName}
renderItem={({ item }) => <ItemRender name={item.name} />}
keyExtractor={item => item.id}
ItemSeparatorComponent={ItemDivider}
**ListHeaderComponent={FlatList_Header}**
ListHeaderComponentStyle={{ borderBottomColor: 'red', borderBottomWidth: 2 }}
/>
Note the use of the ListHeaderComponent in the code above, that should supress the warning.
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>
}
/>
In my case it was happening due to nesting of ScrollView.
Try replacing some of the ScrollView from children components with React.Fragment.
The solution is very simple, please do not put the Flatlist component in the ScrollView.
They both have the same functionality but Flatlist has advantages and is more stable to use.

Can't use both Scrollview and Flatlist within same React Native component

I'm trying to use a Scrollview to scroll horizontally a mapped array and also a Flatlist to scroll vertically a list of items from another array but the combination of the 2 don't seem to work.
This is not a case on wrapping a Flatlist inside a Scrollview which causes a well known problem, I'm not getting the VirtualizedLists warning here.
Here's my code in the rendering section:
return (
<View style={styles.screen}>
<Scrollview style={styles.containerRow}>
{selectedGenres.map((item) => {
return (
<TouchableOpacity
onPress={() => {
genreHandler(item.id, item.name);
}}
style={styles.containerRow}
key={item.id}
>
<View style={styles.filterGenderLayout}>
<Text style={styles.genderButton}>{item.name}</Text>
</View>
</TouchableOpacity>
);
})}
</Scrollview>
<View style={styles.container}>
<View style={styles.containerRow}>
<FlatList
numColumns={3}
data={result}
keyExtractor={(item) => item.id.toString()}
onEndReached={loadMoreCommit}
onEndReachedThreshold={0.5}
renderItem={(itemData) => (
<StarsItem
id={itemData.item.id}
poster={itemData.item.poster_path}
title={itemData.item.title}
onStarsSelection={fetchMovieHandler}
showtitle={false}
/>
)}
/>
</View>
</View>
</View>
As you can see the Scrollview and Flatlist are not nested but I get an error as invalid element. If I use a normal View tag instead of Scrollview, everything looks fine except that I cannot scroll my first list horizontally.
Any suggestion on how to fix this?
I tried to use Flatlist on both however I need the first to scroll horizontally and the second vertically with numColumns={3} meaning I get a different error.

react-native : horizontal scrollview won't work inside flatlist

I have a horizontal scrollview inside my flatlist but it won't scroll.
renderRow = ({ item }) => {
return (
<View style={{width:'100%', backgroundColor:'transparent'}}>
<ScrollView horizontal={true}>
//I have multiple images here
</ScrollView>
</View>
)
}
This is my flatlist
<FlatList
keyExtractor={(item, index) => index.toString()}
data={this.state.data}
renderItem={this.renderRow}
/>
is it possible to put horizontal scrollview inside flatlist?
Try to add style width:100% in ScrollView
<ScrollView horizontal={true} style={{width:'100%'}}>
//I have multiple images here
</ScrollView>
You can try somethig like this:
<ScrollView horizontal={true} style={{flex: 1}}>
//Place Mutiple image in ScrollView.
</ScrollView>