Correct way to use memo in Flatlist react native - react-native

Good evening everyone .
I have created the following Flatlist :
<View style={{ flex: 1 }}>
<FlatList
ListFooterComponent={
loadMore && page < pageMax ? (
<ActivityIndicator color={Colors.grey40} />
) : (
<View />
)
}
ListFooterComponentStyle={{ height: 200 }}
contentContainerStyle={styles.listExercise}
keyExtractor={() => uuid.v4()}
data={exercises}
renderItem={renderItemRE}
removeClippedSubviews={true}
onEndReached={() => {
setOnEndReachedCalledDuringMomentum(true);
}}
onMomentumScrollEnd={loadMoreFc}
onEndReachedThreshold={0.3}
ListEmptyComponent={
<Text contentW B18>
Nessuna Esercizio presente
</Text>
}
/>
</View>
This is renderItem function
const renderItemRE = ({ item }) => {
return (
<RenderItemRE
selectables={route.params?.selectables}
item={item}
navigation={navigation}
/>
);
};
And finally this is my component RenderItemRE
const RenderItemRE = ({ item, navigation, selectables }) => {
return (
<View style={styles.globalContainer}>
<TouchableOpacity
style={styles.touchable}
onPress={() => {
navigation.navigate(Routes.InfoEsercizio, {
id_ex: item.id,
nomeEx: item.nome,
});
}}
>
<View style={styles.container}>
<Image
indicator={Progress}
style={styles.img}
source={{
uri: item.galleria
? item.galleria[0]
? item.galleria[0]
: "logo"
: ApiConstants.DEFAULT_IMAGE,
}}
/>
<Text
style={[
customtext(DYNAMIC_FONTS_SIZE.FONT_SIZE_BIG).regular,
styles.nameStyle,
]}
>
{item.nome}
</Text>
</View>
</TouchableOpacity>
</View>
);
};
function arePropsEqual(prevProps, nextProps) {
return nextProps.item.id === prevProps.item.id;
}
export default memo(RenderItemRE, arePropsEqual);
This is a correct way to use memo in react native ? Or am I doing something wrong? I'm noticing that when the list gets bigger the rendering slows down. I was wondering what was the correct way to optimize. Thank you in advance

Related

How to Send data from from one components flat-list to another component in react native

Categories.js
<FlatList
data={categorylist}
keyExtractor={(item, index) => item.tc_id}
vertical
numColumns={4}
renderItem={({ item, index }) => {
return (
<Pressable onPress={subcat}>
<View style={styles.catLayout}>
<View style={styles.imageLayout}>
<Image source={{ uri: item.image }} style={styles.image}
/>
</View>
<Text style={styles.productname}>
{item.name != null ? item.name : ""}
</Text>
<Text>{item.uuid}</Text>
</View>
</Pressable>
);
}}
/>
I am getting data from categorylist array , i am displaying a bunch of items of categories here , i want show different sub-categories depending on each items "uuid".
I want to send the {item.uuid} to subcategories screen and reuse it in there.
As you are displaying the data on the view using flatlist you have onPress after clicking on any item you just need to send the data
Screen (A)
<FlatList
data={categorylist}
keyExtractor={(item, index) => item.tc_id}
vertical
numColumns={4}
renderItem={({ item, index }) => {
return (
<Pressable onPress={() => navigation.navigate('subcategories',{uuid:item.uuid}) }>
<View style={styles.catLayout}>
<View style={styles.imageLayout}>
<Image source={{ uri: item.image }} style={styles.image}
/>
</View>
<Text style={styles.productname}>
{item.name != null ? item.name : ""}
</Text>
<Text>{item.uuid}</Text>
</View>
</Pressable>
);
}}
/>
Screen (B)
you can get it like this
class component
constructor(props) {
super(props);
this.state = {
uuID: this.props.navigation.state.params.uuid,
}
}
functional component
const Subcategory = (props) => {
const [uUID, setuUID] = useState(props.route.params.uuid);

Why does FlatList scrolls to top when I select an item

I have a FlatList with TouchableOpacity items. When I try to select an item, the list scrolls to top.
This is the Collapsible content;
const setBrandSelected = index => {
var temp = JSON.parse(JSON.stringify(tempFilterOptions));
temp[0].enums[index].selected = !temp[0].enums[index].selected;
setTempFilterOptions(temp);
};
const FilterOptionBrand = () => {
const RenderBrand = ({ item, index }) => {
return (
<TouchableOpacity onPress={setBrandSelected.bind(null, index)}>
{item.selected && (
<View style={[styles.brandImage, styles.selectedBrandImage]}>
<Icon iconName={iconNames.Tick} />
</View>
)}
<FastImage source={{ uri: item.logo }} style={styles.brandImage} resizeMode={FastImage.resizeMode.contain} />
<Text style={styles.brandName}>{item.name}</Text>
</TouchableOpacity>
);
};
const BrandSeparator = () => <View style={styles.brandSeparator} />;
return (
<View style={styles.filterBrandMainContainer}>
<View style={styles.searchBrandContainer}>
<View style={styles.magnifyingGlassWrapper}>
<Icon iconName={iconNames.MagnifyingGlass} />
</View>
<TextInput style={styles.searchBrandInput} placeholder={searchBrandText} />
</View>
<FlatList
horizontal={true}
showsHorizontalScrollIndicator={false}
keyExtractor={(item, index) => String(item.id)}
style={styles.collapsibleContainer}
data={tempFilterOptions[0].enums}
renderItem={RenderBrand}
ItemSeparatorComponent={BrandSeparator}
></FlatList>
</View>
);
};
If you somehow stumble upon this question. The answer is wherever the problem occurs be it Header be it Footer. You should call the component function and not directly just type the function.
const Header = () => <View />
Correct usage;
ListHeaderComponent={Header()}
Incorrect usage;
ListHeaderComponent={Header}

React Native Flatlist with radio buttons works slow

I have flatlist with custom radio buttons implementaion, but when i tap on flatlist item it waits about second before changes to active button. I tried to useCallback with my renderItem and itemKeyExtractor functions but it doesnt help me.
Here is the code of my screen component:
export const PickOrganizationScreen = (props) => {
const { navigation, setOrganization, loadProcedureProviders, items, isLoading, procedureId, organizationId } = props;
useFocusEffect(
React.useCallback(()=>{loadProcedureProviders(procedureId);},[loadProcedureProviders, procedureId])
);
const renderItem = ({item}) => {
return (
<OrganizationItem
title={item.Title}
checked = {item.Id === organizationId}
onPress={() => {
setOrganization(item.Id, item.Title);
}}
/>);
};
const itemKeyExtractor = (item) => item.Id;
return (
isLoading ? (
<Spinner />
) : (
items.length > 0 ? (
<View style={styles.container}>
<View style={styles.paragraph}>
<Text style={styles.subtitle}>{I18n.t('pickOrganization')}</Text>
</View>
<View style={styles.alertMessage}>
<View style={styles.alertIcon}>
<Icon name="info" width={32} height={32} fill={Colors.primaryRed} />
</View>
<View>
<Text style={styles.alertText}>{I18n.t('pickOrganizationToRegisterService')}</Text>
</View>
</View>
<FlatList
data = {items}
renderItem = {renderItem}
keyExtractor = {itemKeyExtractor}
extraData={organizationId}
/>
<View style={styles.buttonWrapper}>
<ScreenButton
title={I18n.t('goToRegister')}
onPress={ () => {
navigation.navigate('ServiceSummary');
}}/>
</View>
</View>
) : (
<NotFound extraText={I18n.t('notFoundExtra')}/>
)
)
);
};
Here is the code of flatlist item component:
export const OrganizationItem = ({title, checked, onPress}) => {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.itemContainer}>
<View style={styles.itemIcon}>
{ checked ? (
<Icon name="radio-button-on" width={16} height={16} fill={Colors.primaryRed} />
) :
(
<Icon name="radio-button-off" width={16} height={16} fill={Colors.gray} />
)
}
</View>
<View style={styles.itemText}>
<Text style={styles.title}>{title}</Text>
</View>
</View>
</TouchableOpacity>
);
};
Try memoizing OrganizationItem. Does the onPress in OrganizationItem change the items object ? If so, it will re-render the whole Flatlist even when one small change is made. If you memoize, the components memoized won't rerender unless the props passed to it changes.
export const OrganizationItem = React.memo(({title, checked, onPress}) => {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.itemContainer}>
<View style={styles.itemIcon}>
{ checked ? (
<Icon name="radio-button-on" width={16} height={16} fill={Colors.primaryRed} />
) :
(
<Icon name="radio-button-off" width={16} height={16} fill={Colors.gray} />
)
}
</View>
<View style={styles.itemText}>
<Text style={styles.title}>{title}</Text>
</View>
</View>
</TouchableOpacity>
);
});

React Native FlatList Delete Item

I want to delete item from the FlatList. However, the solution from here is not working for my code. When I run my code, I am getting error such as 'index is not defined'.
I have yet to find other post regarding this issue so any help would be greatly appreciated.
Code snippet provided below:
export default class FrCreateScreen extends Component {
constructor(props) {
super(props);
this.state = {
//new timeSlots
timeSlots: [],
}
}
setEndTime = (event, appointmentEndTime, textEndTime) => {
appointmentEndTime = appointmentEndTime || this.state.appointmentEndTime;
textEndTime = textEndTime || moment(appointmentEndTime).format('h:mm a').toString();
this.setState({
showEndTime: Platform.OS === 'ios' ? true : false,
appointmentEndTime,
textEndTime,
timeSlots: [
...this.state.timeSlots,
{
apptdate: this.state.textAppointmentDate,
appttime: this.state.textAppointmentTime,
endTime: textEndTime,
}
],
});
}
deleteDateTime = (id) => {
const filteredData = this.state.timeSlots.filter(item => item.id !== id);
this.setState({ timeSlots: filteredData });
}
render() {
return (
<ScrollView>
...
<View>
<FlatList
data={this.state.timeSlots}
keyExtractor={({ id }, index) => index.toString()}
renderItem={({ item }) => {
return (
<View style={styles.containerList}>
...
<TouchableOpacity onPress={() => this.deleteDateTime(index)}>
<Feather name="trash" style={styles.icon} />
</TouchableOpacity>
</View>
</View>
);
}}
/>
</View>
</ScrollView>
)
};
};
Screenshot below:
I think you need to add index inside renderItem { item, index }
renderItem = {({ item, index }) => {
return (
<View style={styles.containerList}>
<TouchableOpacity onPress={() => this.deleteDateTime(index)}>
<Feather name="trash" style={styles.icon} />
</TouchableOpacity>
</View>
);
}}
While rendering in map function , it provides the index too, so try adding that.
renderItem={({ item,index }) => {
return (
<View style={styles.containerList}>
...
<TouchableOpacity onPress={() => this.deleteDateTime(index)}>
<Feather name="trash" style={styles.icon} />
</TouchableOpacity>
</View>
</View>
);
}}
Hope it helps
ok fixed. on touchable onPress, the argument should be 'item.index' instead of 'index'.
here's the correct code:
renderItem={({ item,index }) => {
return (
<View style={styles.containerList}>
...
<TouchableOpacity onPress={() => this.deleteDateTime(item.index)}>
<Feather name="trash" style={styles.icon} />
</TouchableOpacity>
</View>
</View>
);
}}

React Native TouchableHighlight not working with Sectionlist

I've got a SectionList, and for every row in the list I want to be able to detect a click event.
renderList() {
if (this.state.searching) {
return (
<SectionList
sections={this.state.data}
renderSectionHeader={this.props.renderSectionHeader}
renderItem={this.props.renderItem}
/>
);
}
return null;
}
render() {
return (
<View style={styles.container}>
<Animated.View
style={{ opacity: 1 - this.state.backgroundColor }}
pointerEvents={this.state.searching ? 'none' : undefined}
>
{this.props.children}
</Animated.View>
<Animated.View
style={[
styles.backgroundColorView,
{ opacity: this.state.backgroundColor },
]}
/>
<Animated.View
style={[styles.searchResults, { top: this.state.yPos }]}
>
<TextInput
ref={(input) => { this.searchBar = input; }}
style={styles.textInput}
value={this.props.query}
onChangeText={this.onChangeText}
maxLength={100}
placeholder={this.props.placeholder}
onFocus={this.onFocus}
onBlur={this.onUnSearch}
/>
{this.renderList()}
</Animated.View>
</View>
);
For my renderItem method, I'm passing in the following PureComponent, which is just a Text contained in a TouchableHighlight.
class SubjectSearchItem extends React.PureComponent {
render() {
const item = this.props.item;
return (
<TouchableHighlight
onPress={() => console.log(item)}
>
<View style={{
marginHorizontal: 20,
marginVertical: 10,
}}
>
<Text>{`${item.item.long_name} (${item.item.short_name})`}</Text>
</View>
</TouchableHighlight>
);
}
}
and here's the renderItem prop I'm passing in
const renderItem = item => (
<SubjectSearchItem
item={item}
/>
);
The problem is, no click events are being detected. The row isn't getting highlighted, and the onPress isn't being fired. Any ideas?
Note: seems like this has been an issue for a little while