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
}
});
CodePudding user response:
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',
},
});
CodePudding user response:
There are 2 options depending on your needs.
- You could keep your all of your data and selected state in a single stateful array. On press you need to find the item in the array that should update.
import * as React from 'react';
import {
Text,
StyleSheet,
TouchableOpacity,
Button,
FlatList,
SafeAreaView,
} from 'react-native';
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>
);
}
const styles = StyleSheet.create({
flatListTouchable: {
width: '100%',
backgroundColor: 'blue',
color: 'white',
padding: 30,
},
flatListTouchablePressed: {
backgroundColor: 'black',
},
flatListTouchableText: {
color: 'white'
}
});
- You could keep your data and selected state separately. Selected state is managed in the child component.
import * as React from 'react';
import {
Text,
StyleSheet,
TouchableOpacity,
Button,
FlatList,
SafeAreaView,
} from 'react-native';
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>
);
};
const styles = StyleSheet.create({
flatListTouchable: {
width: '100%',
backgroundColor: 'blue',
color: 'white',
padding: 30,
},
flatListTouchablePressed: {
backgroundColor: 'black',
},
flatListTouchableText: {
color: 'white',
},
});