How to fix error VirtualizedLists should never be nested inside plain ScrollViews with the same orientation? - react-native

My application has the 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.", but I don't know how to solve it. In ScrollView I have two Flatlists and a header.
Screen: Flatlists inside my ScrollView
My code:
const renderItem = ({ item }) => <AssuntoCard item={item} />;
return (
<Container> // SCROLLVIEW
<TouchableOpacity
>
<Close />
</TouchableOpacity>
<Titulo>
<Bold>O que vocĂȘ deseja</Bold>
{"\n"}estudar hoje?
</Titulo>
<Subtitulo>Selecione um capĂ­tulo: </Subtitulo>
<Linhas> // View with two columns
<Colunas> // Column 1 for even items
<FlatList
scrollEnabled={false}
data={card.filter((item) => item.id % 2 == 0)}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</Colunas>
<Colunas> // Column 2 for odd items
<FlatList
scrollEnabled={false}
data={card.filter((item) => item.id % 2 !== 0)}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</Colunas>
</Linhas>
<Modal>
// ...
</Modal>
</Container>
);

Related

React-Native FlatList issues in RTL view

I have a Horizontal FlatList and in RTL view the FlatList just constantly call onEndReached method but that's not the case in LTR view.
It's a big issue that's not solved https://github.com/facebook/react-native/issues/19979
Did anyone try to find a workaround for this issue ?
Here is my implementation:
<FlatList
horizontal
directionalLockEnabled
data={recommendedPosts}
onRefresh={handleRefresh}
refreshing={isRefreshing}
onEndReachedThreshold={0.5}
onEndReached={onEndReached}
keyExtractor={(item) => item?._id}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
ListHeaderComponentStyle={styles.footerStyle}
ListFooterComponentStyle={styles.footerStyle}
renderItem={({ item, index }) => (
<AdGridCard
ad={item}
containerStyle={styles.recommendedCard}
onPress={() => goToDetails(item?._id, index)}
/>
)}
contentContainerStyle={styles.contentContainerStyle}
getItemLayout={(d, index) => {
return { length: hp(250), offset: index * hp(250), index };
}}
ListFooterComponent={<LoadingComponent isLoading={loading} />}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>

Last item in React native flat list goes beyond screen

I have a flatlist with some styles on the outer containers as follows.
<View style={containerStyle}>
// more jsx components come here
<View style={resultContainerStyle}>
<FlatList
data={results}
keyExtractor={(item) => (item.id && item.id.toString())}
renderItem={({ item, index }) => (
<ListItem
item={item}
selectItem={selectItem}
/>
)}
/>
</View>
</View>
The issue is that the last values of the list go beyond the view of the screen and there is no way to view it unless a fixed height is put on the parent container. Is it possible to do this without a fixed height.
A SafeAreaView can be used to limit the view to the "safe" areas of the screen(avoiding the notch and curved bottom. Checkout the following example
<SafeAreaView style={containerStyle}>
// more jsx components come here
<View style={resultContainerStyle}>
<FlatList
data={results}
keyExtractor={(item) => (item.id && item.id.toString())}
renderItem={({ item, index }) => (
<ListItem
item={item}
selectItem={selectItem}
/>
)}
/>
</View>
</SafeAreaView>
more examples can be found at the react native docs.

How do I render different data types from a fetched json?

I was using...
<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Text>{item.username} {item.name}</Text>}
keyExtractor={({id}, index) => id}
/>
...to render two texts in React Native but now I've got an uri in my json...
How do I render the image in an IM style (thumbnail, username and name)?
Add a renderItem method and then put everything you need in there. Once you make the renderItem method you can throw it into your FlatList.
renderItem({ item }) {
return (
<View>
<Image
source={{uri: item.uri}}
/>
<Text>
{item.username}
</Text>
<Text>
{item.name}
</Text>
</View>
);
}
Then use the method inside the FlatList (the .bind makes sure it stays in the right context)
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem.bind(this)}
keyExtractor={({id}, index) => id}
/>
You can build a component that takes your fields as its props, containing multiple Texts and an Image using your uri as the source. Style this like you would any other component, and then pass that component into renderItem.
You can embed the component immediately to the renderItem like this if the flatlist item is not complicated ( has a lot of component )
<FlatList
data={this.state.dataSource}
renderItem={({item}) => {
<View>
<Image source={{uri: item.uri.image}}/>
<Text>{item.userName}</Text>
<Text>{item.name}</Text>
</View>
}}
keyExtractor={(i) => i.toString()}
/>

Difference between FlatList and VirtualizedList

I am new in react native, and am confused about the difference between FlatList and VirtualizedList.
So,
What are the differences between FlatList and VirtualizedList ?
When should I use each ?
The <FlatList> is a performant interface for rendering basic, flat lists.
On the other side, the <VirtualizedList> is a base implementation of the <FlatList> and <SectionList> components, which are also better documented. In general, <VirtualizedList> should only really be used if you need more flexibility than FlatList provides, e.g. for use with immutable data instead of plain arrays.
FlatList example:
const App = () => {
const renderItem = ({ item }) => (
<Item title={item.title} />
);
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
VirtualizedList example:
const App = () => {
return (
<SafeAreaView style={styles.container}>
<VirtualizedList
data={DATA}
initialNumToRender={4}
renderItem={({ item }) => <Item title={item.title} />}
keyExtractor={item => item.key}
getItemCount={getItemCount}
getItem={getItem}
/>
</SafeAreaView>
);
}
More info:
https://reactnative.dev/docs/virtualizedlist
https://reactnative.dev/docs/flatlist

onEndReached in Flatlist issue

If I enclose the flatlist in a View then my onEndReached triggers infinitely if I remove the enclosing View onEndReached is not triggered at all.
render() {
return (
<Root>
<Container>
<Content>
<View>
{this.state.listView && (
<FlatList
data={this.state.variants}
keyExtractor={this._keyExtractor}
onEndReachedThreshold={0.5}
onEndReached={({ distanceFromEnd }) => {
console.log(
"on end reached ",
distanceFromEnd
);
this.loadMore();
}}
numColumns={1}
renderItem={({ item, index }) => (
<CatalogRow
item={item}
in_wishlist={this.state.in_wishlist}
toggleWishlist={() =>
this.toggleWishlist(item.title)
}
listView={this.state.listView}
/>
)}
/>
)}
</View>
</Content>
</Container>
</Root>
);
}
And my distanceFromEnd takes values like 0 , 960,1200 when it is trigerred. What does it indicate?
I'm using react-native 0.47.2
I have same problem with react-native 0.50.3
<Flatlist> must not be used in a <ScrollView> if you want to use onEndReached because Flatlist can not found the height.
Use a <View> instead
It was because of the enclosing <Content> tag. Sometimes embedding react-native tags with native-base tags causes such issues. I replaced the content and container tag with View tags and now it works fine.
I have same problem with RN 0.52
That look like because Flatlist can not found the heigh. So he can not find the end of list.
Fix by wrap your flatlist by a View with flex=1
<View style={{flex: 1}} > <Flatlist /> <View>
I would use it like this:
handleMore = () => {
// fetch more here
};
<FlatList
onEndReached={this.handleMore}
/>