react native - I cannot scrolling down with two flatlist - react-native

I can scroll only in case when I change SafeAreaView to ScrollView but I get this error
VirtualizedLists should never be nested inside plain ScrollViews with the same orientation - use another VirtualizedList-backed container instead.
{subCategoryIsLoading ? (
<ActivityIndicator
size='large'
color={primColor}
style={{marginTop: 150}}
/>
) : (
<SafeAreaView>
<View style={styles.containerSubCategory}>
<FlatList
showsVerticalScrollIndicator={false}
data={filterCatTrue()}
keyExtractor={item => item._id}
renderItem={({item}) => {
return (
<View style={styles.containerImages}>
<TouchableHighlight onPress={() => console.log(item._id)}>
<Image
source={{
uri: `${urlImages}subCategories/${item.image}`,
}}
style={styles.imageSubCategory}
/>
</TouchableHighlight>
</View>
)
}}
/>
<FlatList
horizontal={false}
numColumns={2}
showsVerticalScrollIndicator={false}
columnWrapperStyle={{
justifyContent: 'space-between',
}}
data={filterCatFalse()}
keyExtractor={item => item._id}
contentInset={{bottom: 60}}
renderItem={({item}) => {
return (
<View style={styles.containerImagesWide}>
<TouchableHighlight>
<Image
source={{
uri: `${urlImages}subCategories/${item.image}`,
}}
style={styles.imageSubCategoryWide}
/>
</TouchableHighlight>
</View>
)
}}
/>
</View>
</SafeAreaView>
)}

Virtualized lists, that means 'SectionList' and 'FlatList' for example, are performance-optimized meaning they improve memory consumption when using them to render large lists of content. The way this optimization works is that it only renders the content that is currently visible in the window, usually meaning the container/screen of your device. It also replaces all the other list items same sized blank space and renders them based on your scrolling position.
Now If you put either of these two lists inside a ScrollView they fail to calculate the size of the current window and will instead try to render everything, possibly causing performance problems, and it will of course also give you the warning mentioned before.
Check this post, it perfectly explains your problem.

Related

React-Native horizontal FlatList

I have flat list that is returning a JSON feed with nested objects / arrays. All is working except horizontal listing, it still lists each item vertically. Does anyone know how I can list the returned images horizontally instead of vertically?
{isLoading ? <ActivityIndicator/> : (
<FlatList
data={[data]}
horizontal={true}
keyExtractor={({ id }, index) => id}
renderItem= {({ item, index }) => (
<View>
{item.items.map((v, i) => (
<TouchableOpacity onPress={() => props.navigation.navigate('Pdp', {articleid: item.id})}>
<View style={styles.container}>
<Image style={styles.imgyoutubeprev} source={{ uri: chkValue(v.snippet.thumbnails.high.url) }} />
<Image style={styles.imgyoutubebtnoverlay} source={require('../assets/youtubebtn.png')} />
</View>
</TouchableOpacity>
))}
</View>
)}
/>
)}
We would need to have a bit more information about the styles that you are using. If the items are rendered vertically instead of horizontal then this is likely caused by the element that surrounds the FlatList.
Make sure that the View or other component that contains the FlatList has the flex: 1 style or at least takes up the full width. Otherwise the horizontal elements would still wrap and be rendered vertically.
Bonus tip: You might be able to remove the View child from the TouchableOpacity by moving the styles.container to the TouchableOpacity and then replacing the inner View with a Fragment.
Thanks all. The big difference was removing the view surrounding the item.items.map. I haven't had to force flex: 1 against the view, though I have forced flex 1 across the whole screen, so possibly thats helped as well. Thanks again all.
The code I used (taking on your code reduction, and is working as expected is;
return (
<View>
{isLoading ? <ActivityIndicator/> : (
<FlatList
data={[data]}
horizontal={true}
horizontal
keyExtractor={({ id }, index) => id}
renderItem= {({ item, index }) => (
item.items.map((v, i) => (
<TouchableOpacity onPress={() => props.navigation.navigate('Pdp', {articleid: item.id})}>
<Image style={styles.imgyoutubeprev} source={{ uri: chkValue(v.snippet.thumbnails.high.url) }} />
<Image style={styles.imgyoutubebtnoverlay} source={require('../assets/youtubebtn.png')} />
</TouchableOpacity>
))
)}
/>
)}
</View>
);
};

Load items from API in reverse order

I have a react native app that is retrieving APIs.
However, instead of retrieving from item[0] to item[93], I wanted to reverse it so that it presents the data from item[93] at the top, followed by item[92], etc.
Hence, I tried to include this in my flatlist:
inverted={true}
However, in doing so, when i load the app, it will still load from [0], but keep including the next items above it over and over.
How do I also load the info from item[93] to item[0]?
Thanks so much!
My flatlist looks like that:
return (
<View style={styles.background}>
<FlatList
data={this.state.dataSource}
keyExtractor={this._keyExtractor}
inverted={true}
renderItem={({ item }) => (
<Card>
<CardItem>
<View style={styles.container}>
<Image style={styles.profilepic}
source={{
uri: item.links.mission_patch
// from API docs
}}
/>
</View>
<View style={styles.userinfo}>
<Text style={styles.content}>
Flight Number: {item.flight_number}
Mission Name: {item.mission_name}
{item.details}
</Text>
</View>
</CardItem>
</Card>
)}
/>
</View>
);
}
}
You can try the Array.reverse() like so:
<FlatList
data={this.state.dataSource.reverse()}
//

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.

Add one last element to the end of FlatList

I am trying to achieve the following, whereas all but the last are normal images coming from an array.
Currently this is the code for the FlatList:
<FlatList
data={images}
numColumns={3}
// ListFooterComponent={
// <View style={[StyleSheet.actionUploadedPictureFrame , {height: PIC_HEIGHT, width: PIC_WIDTH}]}>
// <Image source={require('../../../images/add-icon.png')} />
// </View>}
renderItem={ ({item, index}) => index == images.length -1 ?
<View style={{flexDirection: 'row'}}>
<Image style={[StyleSheet.actionUploadedPictureFrame , {height: PIC_HEIGHT, width: PIC_WIDTH}]} source={{uri: item.url}} />
<View style={[StyleSheet.actionUploadedPictureFrame , {height: PIC_HEIGHT, width: PIC_WIDTH}]}>
<Image source={require('../../../images/add-icon.png')} />
</View>
</View>
: <Image style={[StyleSheet.actionUploadedPictureFrame , {height: PIC_HEIGHT, width: PIC_WIDTH}]} source={{uri: item.url}} /> }
keyExtractor={(item, index) => index.toString()}
/>
Which long story short, renders the pictures in the array in a table of 3 columns, and checks for the last picture in the list and in addition to rendering the picture, it also renders this plus sign.
However this is bound to have some sort of error if the list has a number of elements multiple of 3, since the plus sign would most likely be out of the screen.
If I use ListFooterComponent, it renders it in an entirely new line.
Does anyone know an effective work around to this?
Since I don't think I was clear enough, I'll try to explain properly my idea with this sample code:
<FlatList
data={[...images, { plusImage: true }]}
numColumns={3}
renderItem={({ item }) => {
if (item.plusImage) {
return (
<View
style={[
StyleSheet.actionUploadedPictureFrame,
{ height: PIC_HEIGHT, width: PIC_WIDTH }
]}
>
<Image source={require("../../../images/add-icon.png")} />
</View>
);
}
return (
<Image
style={[
StyleSheet.actionUploadedPictureFrame,
{ height: PIC_HEIGHT, width: PIC_WIDTH }
]}
source={{ uri: item.url }}
/>
);
}}
keyExtractor={(item, index) => index.toString()}
/>;
I don't know if it's the best practice to concat data array like that directly in the data prop, but you can always choose to declare it earlier in the render method.
Let me know if this can fit your request.
I also came around the same situation and found a good way when I have check the documentation of FlatList so the best way that I recommend is to use ListFooterComponent you can pass a style object for that element using ListFooterComponentStyle Click here for more details.

How to define different list items background images in react native?

In my app, I want different cards have different background images, every image has a number text, and when I click the image it can increase the number by one. now I have them with same image background image, I do not know how to modify my code to meet this requirement. The following is my code:
const MyMeetupsList = ({meetups}) => (
<FlatList
data={meetups}
renderItem={({item}) => (
<View style={{marginLeft:8, marginTop: 8} }>
<View style={styles.meetupCard}>
<ImageBackground source={ require('../../../imgs/food-2.jpg')} style={{width: 175, height: 200}} blurRadius={6}>
<Text style={styles.gridItemText}>{item.title}</Text>
</ImageBackground>
</View>
</View>
)}
numColumns={2}
keyExtractor={item => item.title}
/>
);
Hope you can help! Thanks a lot!
You can use attribute extraData for tracking any change to the dataset and flatlist will rerender on any changes applied on data set. Here i added Map data set( Immutable.js) which can be used to track multiple data sets. If you have only one then you can put that data set straight away. handleClickAction is a function u need to define to mutate your data.
const MyMeetupsList = ({meetups}) => (
<FlatList
data={meetups}
extraData={Map({
foo: meetups, // here you can put any data sets u want to watch for render
})}
renderItem={({item}) => (
<View style={{marginLeft:8, marginTop: 8} }>
<View style={styles.meetupCard}>
<ImageBackground source={ require('../../../imgs/food-2.jpg')} style={{width: 175, height: 200}} blurRadius={6}
onPress = {()=>handleClickAction(item.id)} >
<Text style={styles.gridItemText}>{item.title}</Text>
</ImageBackground>
</View>
</View>
)}
numColumns={2}
keyExtractor={item => item.title}
/>
);
I hope above snippet helps