Reputation: 745
I created a list of data in flatlist and I want that when user click on item it will select that only that item but it's selecting all item. I don't know where did I mistake. Below is my code.
const [state, setState] = useState({
isLoading: false,
search: '',
isClicked: false,
});
const {isLoading, search, isClicked} = state;
<FlatList
data={data}
style={{marginTop: moderateScaleVertical(23)}}
keyExtractor={(data) => data.id.toString()}
renderItem={({item}) => (
<>
{!isClicked && item.id ? (
<TouchableOpacity
style={styles.container}
onPress={() => setState({isClicked: true})}>
<View
style={{
width: moderateScale(18),
height: moderateScaleVertical(18),
backgroundColor: colors.blackOpacity20,
borderRadius: moderateScale(18 / 2),
}}
/>
<Text
style={{
...commonStyles.fontSize15,
color: colors.themeColor,
marginLeft: moderateScale(18),
}}>
{item.tag}
</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
style={styles.container}
onPress={() => setState({isClicked: false})}>
<Image
source={imagePath.checkboxActive}
style={{
width: moderateScale(18),
height: moderateScaleVertical(18),
borderRadius: moderateScale(18 / 2),
}}
/>
<Text
style={{
...commonStyles.fontSize15,
color: colors.themeColor,
marginLeft: moderateScale(18),
}}>
{item.tag}
</Text>
</TouchableOpacity>
)}
</>
)}
/>
I don't what I did wrong here. can someone please help
Upvotes: 0
Views: 1654
Reputation: 105
You are using a state variable isClicked
to check if an item is selected, but since that state is the same for the entire component, once the isClicked
is set to true, all items of the Flatlist will be re-rendered as selected because they will be checking the same variable. What you could do to achieve your goal is to put a isClicked flag individually inside each item, so only the item's flag is set to true once you click on it.
Something like:
<FlatList
data={data}
style={{marginTop: moderateScaleVertical(23)}}
keyExtractor={(data) => data.id.toString()}
renderItem={({item}) => (
<>
{item.isClicked && item.id ? (
<TouchableOpacity
style={styles.container}
onPress={() => item.isClicked = true}>
<View
style={{
width: moderateScale(18),
height: moderateScaleVertical(18),
backgroundColor: colors.blackOpacity20,
borderRadius: moderateScale(18 / 2),
}}
/>
<Text
style={{
...commonStyles.fontSize15,
color: colors.themeColor,
marginLeft: moderateScale(18),
}}>
{item.tag}
</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
style={styles.container}
onPress={() => item.isClicked = false}>
<Image
source={imagePath.checkboxActive}
style={{
width: moderateScale(18),
height: moderateScaleVertical(18),
borderRadius: moderateScale(18 / 2),
}}
/>
<Text
style={{
...commonStyles.fontSize15,
color: colors.themeColor,
marginLeft: moderateScale(18),
}}>
{item.tag}
</Text>
</TouchableOpacity>
)}
</>
)}
/>
Upvotes: 1
Reputation: 2518
Your isClicked local state is common for all the elements of your list, meaning that if you trigger it all of them will have it as true.
The best way to solve this issue would be not to pass a boolean to isClicked but rather the item.id:
onPress={() => setState({isClicked: item.id})}>
and then
{isClicked !== item.id && item.id ? (
Also be careful, you are not maintenaing the state of search and isLoading with your way of updating the state, you should actually rather have:
onPress={() => setState({isLoading, search, isClicked: item.id})}>
If you need to handle multiple possible items clicked at the same time I'd recommend separating each item in their own component with their own isClicked state OR having an array of id for the isClicked values
Upvotes: 1