Reputation: 37
Beginner developer react native.
im dealing with design pattern issue , i have multiple TouchableOpacity's in the same component (i have to keep it that way). for each one i have onPress function thats changs there background and reverse . the problom is that the function dependent on State current statment and when i click on one of them evreyone is changing .
function Grocery({ navigation }) {
const [isPressed, setIsPressed] = useState(0);
const onPress = () => setIsPressed(!isPressed);
return (
<ScrollView>
<Button title="home" onPress={() => {FindMatch(GetIngridients());navigation.navigate("MatchedRecipiesScreen");}}>press</Button>
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={() => {AddToPanetry("pasta");onPress();}} >
<View style={isPressed && styles.pressedButtonStyle} />
<Image style={styles.imageright} source={require('../assets/Pastaa.jpg')} />
<Text> pasta</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {AddToPanetry("eggs");onPress();}} >
<View style={isPressed && styles.pressedButtonStyle} />
<Image style={styles.imageleft} source={require('../assets/eggs.jpg')} />
<Text>eggs</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {AddToPanetry("fish");onPress();}} >
<View style={isPressed && styles.pressedButtonStyle} />
<Image style={styles.imageleft} source={require('../assets/fish.jpg')} />
<Text>fish</Text>
</TouchableOpacity>
const styles = StyleSheet.create({
container: {
flexDirection: "row",
flexWrap: "wrap",
padding: 50,
flexWrap: 'wrap',
justifyContent: 'space-between',
}
,
imageleft: {
borderRadius:100,
borderWidth:2,
borderColor:'black',
height: 120,
width: 150,
borderRadius: 80,
padding:25
},
button: {
alignItems: "center",
},
tinyLogo: {
width: 50,
height: 50,
},
pressedButtonStyle: {
position:"absolute",
width:150,
height:121,
backgroundColor:'black',
opacity:0.6,
zIndex:100,
borderRadius:80
},
imageright: {
borderRadius:100,
borderWidth:2,
borderColor:'black',
height: 120,
width: 150,
borderRadius: 80,
padding:25
}
});
Upvotes: 2
Views: 1373
Reputation: 20821
There are 2 options depending on your needs.
selected
state in a single stateful array. On press, you need to find the item in the array that will update.export default function Grocery({ navigation }) {
const [state, setState] = React.useState([ { label: 'pasta', pressed: false, }, { label: 'eggs', pressed: false, }, { label: 'fish', pressed: false, }, { label: 'salad', pressed: false, }, ]);
const handlePress = (i) => {
const newState = [...state];
newState[i].pressed = !state[i].pressed;
setState(newState);
};
return (
<SafeAreaView style={{ flex: 1 }}>
<FlatList
data={state}
ListHeaderComponent={() => (
<Button
title="home"
onPress={() => {console.log('press home')}}>
press
</Button>
)}
renderItem={({ item, index }) => (
<TouchableOpacity
key={index}
id={index}
onPress={() => handlePress(index)}
style={[
styles.flatListTouchable,
item.pressed && styles.flatListTouchablePressed,
]}>
<Text style={styles.flatListTouchableText}>{item.label}</Text>
</TouchableOpacity>
)}
/>
</SafeAreaView>
);
}
selected
state separately. The selected
state is managed in the child component.const data = [ { label: 'pasta', }, { label: 'eggs', }, { label: 'fish', }, { label: 'salad', }, ];
export default function Grocery({ navigation }) {
return (
<SafeAreaView style={{ flex: 1 }}>
<FlatList
data={data}
ListHeaderComponent={() => (
<Button
title="home"
onPress={() => {
console.log('press home');
}}>
press
</Button>
)}
renderItem={({ item, index }) => (
<RenderItem item={item} index={index} />
)}
/>
</SafeAreaView>
);
}
const RenderItem = ({ item, index }) => {
const [pressed, setPressed] = React.useState(false);
const handlePress = () => {
setPressed(!pressed);
};
return (
<TouchableOpacity
key={index}
id={index}
onPress={handlePress}
style={[
styles.flatListTouchable,
pressed && styles.flatListTouchablePressed,
]}>
<Text style={styles.flatListTouchableText}>{item.label}</Text>
</TouchableOpacity>
);
};
Upvotes: 1
Reputation: 653
One of the approaches is to store item names in an array or object and then check if the particular item were selected.
Here is another approach you could use:
const HomeScreen = () => {
const itemsData = [
{ name: 'Eggs', image: 'image require here', isSelected: false },
{ name: 'Pasta', image: '', isSelected: false },
{ name: 'Fish', image: '', isSelected: false },
];
const [items, setItems] = useState(itemsData);
const handleSelectItem = (selectedItemIndex) => {
const itemsToSelect = items.map((item, index) => {
if (selectedItemIndex === index) item.isSelected = !item.isSelected;
return item;
}, []);
setItems(itemsToSelect);
// your logic here
// AddToPanetry(item[selectedItemIndex].name)
};
const renderItem = (item, index) => {
const isSelected = items[index].isSelected;
return (
<TouchableOpacity
style={[styles.button, isSelected && styles.selectedButton]}
onPress={() => handleSelectItem(index)}>
{/* <Image source={item.image} /> */}
<Text>{item.name}</Text>
</TouchableOpacity>
);
};
return (
<View>
<ScrollView>
{itemsData.map((item, index) => renderItem(item, index))}
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
button: {
backgroundColor: 'white',
padding: 20,
},
selectedButton: {
backgroundColor: 'pink',
},
});
Upvotes: 4