CheckBox in FlatList - react-native

I would like to present the user with a list of items to choose from. The items are sourced from a Redux state object. It is a list of the contacts on the device.
I used a "FlatList" from React-Native and a "ListItem" from React-Native-Elements. The ListItem has a CheckBox.
For the user to check/uncheck an item in the list, he/she can click on the CheckBox or any part of the ListItem.
My 1st Attempt: As you can see in the following code, I had to duplicate part of the code to achieve this. Is there a smarter way of doing this (to avoid code duplication)?
<FlatList
keyExtractor={(item, index) => index.toString()}
data={props.contactList}
renderItem={_renderItem}
ListEmptyComponent={<Text>There are no contacts to show.</Text>}
refreshing={state.refreshing}
onRefresh={_onRefresh}
/>
const _renderItem = ({ item, index }) => {
return (
<ListItem
title={item.name}
onPress={() => {
// The following 2 statements are repeated (below)!!!
_toggleCheck(index);
props.acContactSelect(index);
}}
checkBox={{
checked: _isItemChecked(index),
checkedIcon: "check",
onPress: () => {
// The following 2 statements are repeated (above)!!!
_toggleCheck(index);
props.acContactSelect(index);
},
}}
/>
);
};
My 2nd Attempt: I tried using a function. I got the error message (Maximum update depth exceeded.)
<FlatList
.. {similar to the code above}
/>
const _renderItem = ({ item, index }) => {
return (
<ListItem
..
onPress={_onPress(index)}
checkBox={{
..
onPress: _onPress(index),
}}
/>
);
};
const _onPress = (index) => {
_toggleCheck(index);
props.acContactSelect(index);
};
Thanks for your effort and time to help...

Please change this code
<ListItem
..
onPress={_onPress(index)}
checkBox={{
..
onPress: _onPress(index),
}}
/>
to
<ListItem
..
onPress={() =>_onPress(index)}
checkBox={{
..
onPress:() => _onPress(index),
}}
/>
onPress={_onPress(index)} will call function immediately

Related

Flatlist freezes when `onEndReached` is triggered

I'm using react native and I have a flatlist that can render anywhere from 2 items to over 2000. Due to this, it's really important to optimize the performance to make sure the Flatlist doesn't lag. I've tried to optimize performance with the props provided in the docs. However, I noticed when I scroll down to the bottom and my loadMoreData function is called, scrolling freezes for like 1 second. How can I make it so this doesn't happen? Thank you.
Code:
const [data, setData] = React.useState(mockData);
// Load more data
const loadMoreData = () => {
setData((prevItems) => {
return [...new Set([...prevItems, ...testItem])]; // 'testItem' is an array with one object that
});
};
return (
<FlatList
extraData={data}
data={data}
getItemLayout={(data, index) => ({
length: 78,
offset: 78 * index,
index,
})}
initialNumToRender={7}
maxToRenderPerBatch={10}
windowSize={10}
onEndReached={loadMoreData} // freezes when this is called
onEndReachedThreshold={0.1}
removeClippedSubviews={true}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => (
<>
<Swipeable renderRightActions={(progress, dragX) =>}>
<HoldItem items={InventoryHoldMenuItems}>
<Layout>
<InventoryItem item={item} />
</Layout>
</HoldItem>
</Swipeable>
</>
)}
/>
)}
)

Nesting React-Native FlatList Components and receiving both items

I'm trying to display a FlatList of items, with each item containing a FlatList of identical buttons. When one of the buttons is clicked, I want to receive both the parent FlatList item and the value the button corresponds to.
I've tried the following method with no success (timeItem is undefined):
timeSlotsKeyExtractor = (item, index) => item.toString();
timeSlots =
[
'8:00', '10:00', '12:00', '14:00', '16:00', '18:00'
];
renderDate = ({ item }) => {
return (
<View>
<Text>{item.date}</Text>
<FlatList
data={this.timeSlots}
keyExtractor={this.timeSlotsKeyExtractor}
renderItem={({ timeItem }) => (
<TouchableOpacity onPress={() => this.addTimeSlot(item, timeItem)}>
<View><Text>{timeItem}</Text></View>
</TouchableOpacity>
)}
horizontal={true} />
</View>
)
}
addTimeSlot(item, timeItem) {
console.log(item)
console.log(timeItem)
}
I'm aware of SectionLists, and as such also attempted to make each item of my parent FlatList an object containing both the item and the array of timeSlots, however, I wasn't sure how to go about getting the header in the renderItem section:
Screenshot of SectionList code:
<SectionList
sections={this.state.weekDates}
renderSectionHeader={({ section }) => (
<Text>{section.date} </Text>
)}
renderItem={({ item }) => (
<Text>
{iten.date}
{item.timeSlots}
</Text>
)}
keyExtractor={(item, index) => index}
/>
Where am I going wrong with these approaches? I'm fairly new to React Native so there's a good chance I've missed something really simple.

Remove item from FlatList in react native

I am using Flat List in react native to select Multiple images from gallery. Now i want to remove some of image before uploading it to server. I am not sure how to perform that action.
Here is my code...
<FlatList
style={{ paddingBottom: 5, paddingTop: 10 }}
data={this.state.imagesAddFile}
keyExtractor={(y, z) => z.toString()}
renderItem={({ item }) => (
<SelectedLayout
ImageName = {item.name}
/>
)}
/>
Here i am getting list of images properly but not sure how to delete image from list please suggest am answer. Thanks
I am using delete function like below method sharing all the code here:
Step 1: Render view in add a TouchableOpacity like below code:
<TouchableOpacity onPress={() => this.deleteAddress(itemData.item._id)}>
<Icon name="trash" style={{paddingLeft: 10,paddingRight:10}} size={20} color="red" />
</TouchableOpacity>
Step 2: Add a confirmation box like below code:
deleteAddress(id) {
Alert.alert(
'Delete Address',
'Are you sure want to delete this address ?',
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'OK', onPress: () => this.deleteAddressDetail(id)},
],
{ cancelable: false }
)
}
Step 3: Call your API or anything here:
deleteAddressDetail(id) {
//Delete api or anything here
//after that call your list so updated state data will render
}
Your updated flatlist code:
<FlatList
data={this.state.addressList}
keyExtractor={this._keyExtractor}
extraData={this.state}
renderItem={this.renderRowItem}
/>
Use render item like below code:
renderRowItem = (itemData) => {
<TouchableOpacity onPress={() => this.deleteAddress(itemData.item._id)}>
<Icon name="trash" style={{paddingLeft: 10,paddingRight:10}} size={20} color="red" />
</TouchableOpacity>
}
Well, you could remove the desired item based on it's index.start with modifying the flatList
<FlatList
style={{ paddingBottom: 5, paddingTop: 10 }}
data={this.state.imagesAddFile}
keyExtractor={(y, z) => z.toString()}
renderItem={({ item,index }) => (
<SelectedLayout
onPress={(index) =>this.removeItemFromList(index)}
ImageName = {item.name}
/>
)}
/>
you should wrap the component SelectedLayout inside a TouchableOpacity in order to implement onPress or whatever way you like it. if you could provide me with it's code I could show you.
now the removeItemFromList Implementation we're gonna use splice to remove it from imagesAddFile state.
removeItemFromList(index){
let newimagesAddFile = this.state.imagesAddFile;
newimagesAddFile.splice(index,1); //to remove a single item starting at index
this.setState({imagesAddFile:newimagesAddFile})
}
Since you code is not complete in your question, I assume that your SelectedLayout component might be having TouchableOpacity or something similar to handle tap (to select or remove image).
Basically what you want is to modify the datasource of your Flatlist (i.e this.state.imagesAddFile array) from SelectedLayout component.
Create a function in the component containing the flatlist that receives the image name (or image url depending on the structure of your image object) and that function should remove that image from your state (imagesAddFile). Now pass this function as a prop to your SelectedLayout and call this function from SelectedLayout component in onPress of your Touchable**** in SelectedLayout. You can use lodash methods are they are very handy and well written.(You'd be using them a lot)
Your component might look something like this:
handleImageTap = (imageName) => {
const { imagesAddFile } = this.state;
this.setState({
imagesAddFile: _.filter(imagesAddFile,imageObj =>
imageObj.name !== imageName);
})
}
render() {
return(
<FlatList
style={{ paddingBottom: 5, paddingTop: 10 }}
data={this.state.imagesAddFile}
keyExtractor={(y, z) => z.toString()}
renderItem={({ item }) => (
<SelectedLayout
ImageName = {item.name}
handleImageTap = {this.handleImageTap}
/>
)}
/>
)
The line
_.filter(imagesAddFile,imageObj => imageObj.name !== imageName);
is nothing but just a JSX shorthand inside lodash filter method, which is taking imagesAddFile array, iterating over it and returning new array by removing the image object which is having the name equal to image name. Please refer the doc for better clarification.
Ideally you should be checking first whether the image exist in the array or not. Also i'd suggest not to play with image name, use something unique like id, or imageUrl

(React Native) Change color to a text after onPress() it

I have a drawer with some text elements created dynamically.
I would like to select an item from the drawer, "show selected item" (like change the color of the text of that item) and re-change it to default when another one item is selected.
The text that I'd like to "change onPress" is inside the <TouchableWithoutFeedback> tag (i'm rendering some HTML code with react-native-render-html)
<FlatList
ItemSeparatorComponent={this.FlatListItemSeparator}
data={this.state.data}
renderItem={({ item }) => (
//on touch --> open article (call _onTextPress)
<TouchableWithoutFeedback onPress={this.navigateToScreen('Category', {id: item.id, title: item.name})}>
<View style={styles.categories}>
<HTML html={'<p style="color:#fd3a18; font-size:20px;"><strong>'+item.name+'</strong></p>\n'}/>
</View>
</TouchableWithoutFeedback>
)}
keyExtractor={({ id }, index) => id.toString()}
/>
navigateToScreen(routeName, params) {
return () => {
this.props.navigation.dispatch(NavigationActions.navigate({ routeName, params }))
this.props.navigation.closeDrawer();
};
}
If I understood correctly you want to change the color of selected item
//Add Selected Item to the State
state = {selectedItemId:'myId'}
// Change The State Whenever Selected
navigateToScreen(routeName, params) {
this.setState({selectedItemId:params.id})
return () => {
this.props.navigation.dispatch(NavigationActions.navigate({ routeName, params }))
this.props.navigation.closeDrawer();
};
}
Now Change the color conditionally.
<FlatList
ItemSeparatorComponent={this.FlatListItemSeparator}
data={this.state.data}
renderItem={({ item }) => (
//on touch --> open article (call _onTextPress)
<TouchableWithoutFeedback onPress={this.navigateToScreen('Category', {id: item.id, title: item.name})}>
<View style={styles.categories}>
<HTML html={`<p style="color:${this.state.selectedItemId == item.id ? "red" : "#fd3a18"}; font-size:20px;"><strong>'+item.name+'</strong></p>\n`}/>
</View>
</TouchableWithoutFeedback>
)}
keyExtractor={({ id }, index) => id.toString()}
/>

React-Native : calculating the scrollToItem of a FlatList with a ref on componentDidMount and rendering it

I have a FlatList which renders numbers from 1-10 along with a radio button. If I have pre-selected number which could be dynamic, that numbered radio button is pre-selected. How to calculate the scrollToItem/scrollToIndex in this case ?
componentDidMount() {
this.scrollToItem();
}
scrollToItem = () => {
let dynamicIndex = dynamicIndex
//calcuate the dynamic Index
this.flatListRef.scrollToIndex({ animated: true, index: dynamicIndex });
};
<FlatList
ref={ref => {this.flatListRef = ref;}}
bounces={false}
keyExtractor={item => item.id}
data={listData}
renderItem={({ item, index })=>
this.renderItem(item,index)}
/>
But it throws error "Cannot read property 'scrollToIndex' of index. Basically it can't find 'this.flatListRef' during component mount.