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

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.

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

react native - I cannot scrolling down with two flatlist

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.

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

How to create swipeable bottom sheet in React Native?

How to implement exactly the same swipeable bottom sheet in React Native:
react-swipeable-bottom-sheet (demo gif above) lib is working only in React.
I know react-native-overlay-section but it is opening to the top of the window with bounce animation.
EDIT
I also tried react-native-touch-through-view, but there is a known issue with touches through the TouchThroughView...
<View style={styles.container}>
<View style={styles.contentContainer}>
<FlatList
data={this.state.list}
renderItem={(data) => {
<View>
<Text>{"Bla bla bla"}</Text>
<TouchableOpacity onPress={()=> this.onPress()}>
<Text>{"THIS IS NOT WORKING ON ANDROID"}</Text>
</TouchableOpacity>
</View>
}} />
</View>
<TouchThroughWrapper style={styles.scrollWrapper}>
<ListView
style={styles.scroller}
dataSource={actionsList}
renderHeader={() => <TouchThroughView style={styles.touchThroughView} />}
renderRow={(rowData) => {
return (
<Text style={styles.itemRow}>{rowData}</Text>
)
}}>
</ListView>
</TouchThroughWrapper>
You can achieve your requirement with the help of following package.
https://www.npmjs.com/package/react-native-touch-through-view
This package allows scroll views and table views to scroll over interactable content without poor performing size and bounds animations.

ScrollView cuts off last object on the page

I built a view that is populated dynamically using array mapping. After doing this, I realized that the View would be too large to contain all the array items on one screen.
Here is my code.
<View style={[styles.flexColumn]}>
{Characters.map((character, i) =>
<View key={i} style={[styles.flexRow]}>
<View>
<Text>
{character.Name}
</Text>
</View>
</View>
)}
</View>
So I tried adding a scroll view as the parent like this:
<ScrollView>
<View style={[styles.flexColumn]}>
{Characters.map((character, i) =>
<View key={i} style={[styles.flexRow]}>
<View>
<Text>
{character.Name}
</Text>
</View>
</View>
)}
</View>
</ScrollView>
This does add some scrollability to the view, but it's still cutting off a portion of the last object in the array.
Is there a way to fix this?
Thanks!
ScrollView is intended for showing scrollable content at once. Since you are populating content dynamically, you should be using FlatList. Something similar to the following would work:
...
_keyExtractor = character => character.Name
_renderItem = ({character}) => (
<Text>
{character.Name}
</Text>
)
render() {
return (
<FlatList
data={Characters}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
)
}
...
Detailed explanation is available in the docs.
If you are by any reason still forced to stick to Scrollview, the problem is probably related to the styling. I suppose styles.flexColumn should be applied to the ScrollView itself via contentContainerStyle, rather than to its' child View.