weird results from flatlist in react native with touchable opacity - reactjs

I have a FlatList in a React Native project. The touchable opacity does register as the view loads, for each row, the console prints selected item.name.. (so, without being touched) however, touching the item does not do anything.
render() {
return(
<FlatList
data={stores.databaseStore.sites.slice()}
keyExtractor={ (item, index) => item.id}
numColumns={1}
extraData={stores.databaseStore.isLoadingSites}
onRefresh={() => this.onRefresh()}
refreshing={stores.databaseStore.isLoadingSites}
renderItem={({item}) => this._renderFlatListItem(item)}
ItemSeparatorComponent={this._renderSeparator}
ListHeaderComponent={this._renderHeader}
ListFooterComponent={this._renderFooter}
/>
)
}
_renderFlatListItem(item) {
return (
<View style={styles.row}>
<TouchableOpacity onPress={this._showSiteDetails(site)}>
<View style={styles.cellLeft} >
<PivotCircle site={item}/>
</View>
</TouchableOpacity>
</View>
)
}
_showSiteDetails(site){
console.log(`selected ${site.name}`);
}

found it with the help of some gents on slack
onPress={this._showSiteDetails(site)}
should be
onPress={ () => this._showSiteDetails(item)}

Related

Scroll to position with scrollview

I have a scrollview which has a flatlist nested inside of it, so now I want to scroll to a certain position of the scrollview on button press, how can I achieve this?
Here is my code:
<ScrollView
ref={verticalRef}
>
{
data.map( item => (
<View>
<Text style={styles.title}>{item.title}</Text>
<View >
<FlatList
data={item.data}
numColumns={2}
renderItem={thitem}
/>
</View>
</View>
))
}
</ScrollView>
Here is the handler for the scroll:
const scrollToActiveIndex = (index) => {
setActiveIndex(index)
verticalRef.current?.scrollTo({
x: width * index,
animated: true
})
}
I have also attached a screenshot of my app. Thanksenter image description here

How to get the number of items rendered in a Flat list?

I have a flatlist that sends data to another component where the data got filtered, then the flatlist renders the filtered items. I want to get the number of items rendered by the flatlist (i.e the number of remaining items after the data got filtered). How should I do it, please?
Here is the flatlist
<FlatList
style={styles.scrollContainer}
data={this.state.schedules}
keyExtractor={item => item.id.toString()}
horizontal={false}
showsHorizontalScrollIndicator={false}
renderItem={({ item }) => <Today schedule={item} updateSchedule={this.updateSchedule}/>}
keyboardShouldPersistTaps="always"
/>}
And the component that filters the data;
{schedule.once && today == schedule.date ?
<TouchableOpacity
onPress={() => this.toggleScheduleModal()}
>
<View style={[styles.listContainer, {borderLeftWidth: 4}, {borderLeftColor: schedule.color}]}>
<View style={styles.time}>
<Text style={styles.timeText}>{schedule.stime}</Text>
<Text style={styles.timeText}>{schedule.etime}</Text>
</View>
<View style={styles.title}>
<Text style={styles.noteText} numberOfLines={1}>
{schedule.name}
</Text>
<Text style={styles.subtitle} numberOfLines={1}>
{schedule.type}
</Text>
</View>
<View style={styles.day}>
<Text style={styles.subtitle} numberOfLines={1}>
Today
</Text>
<Text style={styles.subtitle} numberOfLines={1}>
{schedule.teacher}
</Text>
</View>
</View>
</TouchableOpacity>
:
[]
}
The data got filtered and is rendered as expected. I just want to know how to count the numbers. Help please.
I believe you could use the method Children.toArray(children) to count how many rendered items there are.
I couldn't figure out where you'd use it in your specific structure, but you'd need to pass the childrenprop to that method. Children, in this case, I believe would be the component you're filtering your data in.
Another option would be to filter the data before rendering you component, which then would just be a matter of getting the array length.
const filterData = () => {
// need to define `today` here
const filteredSchedules = this.state.schedules.filter(schedule => schedule.once && today == schedule.date);
console.log(filteredSchedules.length);
return filteredSchedules;
}
<FlatList
style={styles.scrollContainer}
data={filterData()}
keyExtractor={item => item.id.toString()}
horizontal={false}
showsHorizontalScrollIndicator={false}
renderItem={({ item }) => <Today schedule={item} updateSchedule={this.updateSchedule}/>}
keyboardShouldPersistTaps="always"
/>}
You can try this current rendered index.
onViewableItemsChanged = ({ viewableItems, changed }) => {
console.log("Visible items are", viewableItems);
console.log("Changed in this iteration", changed);
}
<FlatList
onViewableItemsChanged={this.onViewableItemsChanged }
viewabilityConfig={{
itemVisiblePercentThreshold: 50
}}
/>

clickable Flat list items in React Native

I have a flat list that displays a list of item, I would like to make each item clickable.
My render function looks like this, and it works without any issue, except that it is not clickable
render() {
return (
<FlatList
data={formatData(data, numColumns)}
style={styles.container}
renderItem={this.renderItem}
numColumns={numColumns}
/>
);
}
I have tried to do something similar to this but it is giving me an error, any idea what's wrong with my code?
<FlatList
data={formatData(data, numColumns)}
style={styles.container}
renderItem={({this.renderItem}) => (
<TouchableHighlight
onPress={() => console.log("hello")}>
</TouchableHighlight>
)}
numColumns={numColumns}
/>
You can do like this :
renderItem with TouchableOpacity. Make sure to import it from react native.
import { TouchableOpacity } from "react-native";
import Icon from 'react-native-vector-icons/FontAwesome5';
...
...
render() {
return (
<FlatList
data={formatData(data, numColumns)}
style={styles.container}
renderItem={({item ,index}) => (
<TouchableOpacity
key={index.toString()}
onPress={() => console.log("clicked")}
>
<Icon name={item} color="red"/>
</TouchableOpacity>
)}
numColumns={numColumns}
key={numColumns.toString()} // if you want to use dynamic numColumns then you have to use key props
/>
);
}
First you need to import Touchable Opacity and the error you are getting , make sure data you are passing to flatlist is an array. So check this :
<FlatList
data={formatData(data, numColumns)} // this should be an array , or array of objects
renderItem={({item ,index}) => (
<TouchableOpacity
onPress={() => console.log("hello")}
>
<Text>Hi</Text>
</TouchableOpacity>
/>
Hope its clear
This is how you can iterate inside FlatList itself.
Working live https://snack.expo.io/#akhtarvahid/flatlist-simple
<FlatList
data={formatData(data, numColumns)}
style={styles.container}
renderItem={({item ,index}) => (
<TouchableOpacity
key={index.toString()}
onPress={() => console.log('Clicked item')}>
<Text>{'Hello'}</Text>
</TouchableOpacity>
)}
numColumns={numColumns}
keyExtractor={item=>item.id}
/>

React Native Flatlist header re-rendering when scroll

I am new to React Native and I am having problems with the header in a FlatList.
The header re-renders as soon as I start to scroll, this creates a flickering effect on the images I have in the header.
I have been searching for an answer everywhere but I have not find a posible solution.
¿how could I configure it to stop re-rendering the header when scrolling the list?
....
const Item = ({ title }) => {
return (
<View style={styles.card}>
<Text style={styles.title}>{title}</Text>
</View>
);
};
const listHeader = () => {
const categoriesButtons = categories.map(cat => (
<CategoryButton
text={cat.name}
icon={cat.code}
key={cat.code}
onPress={() => {
//#Todo logic to filter promotions accordingly with the category pressed
}}
/>
));
return (
<View>
<View style={styles.filtersContainer}>
<ImageBackground
source={images.bgShape}
style={{ width: '100%', height: 140 }}
resizeMode="stretch"
>
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
{categoriesButtons}
</ScrollView>
</ImageBackground>
</View>
<View style={styles.breadcrumbContainer}>
<Breadcrumbs navigation={navigation} stack={routes} />
</View>
<View style={styles.titleContainer}>
<Text style={sharedStyles.titleText} id="main-title">
¡{totalOfPromotions} promociones activas en Medellín!
</Text>
</View>
</View>
);
};
return (
<LinearGradient
colors={[Colors.BG_START, Colors.BG_END]}
style={styles.mainContainer}
>
{loading ? (
<ActivityIndicator size="large" color="#000000" />
) : (
<FlatList
data={promos}
renderItem={({ item }) => <Item title={item.title} />}
keyExtractor={(item, index) => index.toString()}
ListHeaderComponent={listHeader}
showsVerticalScrollIndicator={false}
onEndReached={showPromos}
onEndThreshold={0.7}
/>
)}
</LinearGradient>
);
};
listHeader() function is being called more than once because in Flatlist tag should be called as
<FlatList
data={promos}
renderItem={({ item }) => <Item title={item.title} />}
keyExtractor={(item, index) => index.toString()}
ListHeaderComponent={listHeader()}
showsVerticalScrollIndicator={false}
onEndReached={showPromos}
onEndThreshold={0.7}
/>
Use () while assigning ListHeaderComponent prop. By this way, function will be invoked only once.
Hope this help you. Enjoy coding!
From what I can see in the code you provided that you are defining the ListHeader component inside your other parent component which will redfine it on every render.
Moving it might outside the parent component might help.
You can fix your flickering issue by memoizing your ListHeaderComponent.
In your case just wrap your component with useMemo:
const listHeader = useMemo(() => {
...
})

How to get object ID onPress and pass that value on to a new screen in React Native?

I've build an React Native app which shows a list of different objects on the ListScreen. I now want to with onPress show one object values on the ViewScreen
I've build my app using React-Redux and React-navigation now I'm not sure if I should store the data of the object in the store, but I'm not sure if that's the right way to use the Redux store (because I currently use it for the cart items) or If there is another way to pass on these value's on to the ViewScreen.
This is a simplification of my app:
I've made a static Data.js file to test app
Data.JS
`id: 0,
name: 'John Doe',
age: '15',
gender: 'male',
`
Then I import the data into the ListScreen
List.js
`import { object} from './Data';
state = {
object,
};
renderRow = (rowData) => {
return (
<View>
<TouchableOpacity onPress={() => this.props.id.navigation.navigate('ViewScreen')}>
<View>
<Text>
{rowData.item.name}
</Text>
</View>
</TouchableOpacity>
</View>
)
}
render() {
return (
<View>
<FlatList
renderItem={this.renderRow}
keyExtractor={(item, index) => index.toString()}
/>
</View>
)
}
`
ViewScreen
` state = {
object,
};
renderRow = (rowData) => {
return (
<View>
<TouchableOpacity onPress={() => this.props.id.navigation.navigate('ViewScreen')}>
<View>
<Text>
{rowData.item.name}
{rowData.item.age}
{rowData.item.gender}
</Text>
</View>
</TouchableOpacity>
</View>
)
}
render() {
return (
<View>
<FlatList
renderItem={this.renderRow}
keyExtractor={(item, index) => index.toString()}
/>
</View>
)
}
`
How do I pick it up from here? So that the value's get shown in the ViewScreen
you are almost there just add this second argument to your on press method and it's done.
You will get this data in data prop of next screen.
renderRow = (rowData) => {
return (
<View>
<TouchableOpacity onPress={() =>
this.props.id.navigation.navigate('ViewScreen',{data : rowData})}>
<View>
<Text>
{rowData.item.name}
{rowData.item.age}
{rowData.item.gender}
</Text>
</View>
</TouchableOpacity>
</View>
)
}

Resources