I've been several days stuck with this code. I'm trying to make a restaurant cart where each of the product of the flatlist have a + and a minus button and i cant find how to do it. Iwas thinking of using a list of objects as an state, but i can't find a way to work.
const renderProduct = ({ item }) => {
// console.log(JSON.stringify(prodUnit))
return (
<ImageCard
imageUri={item.image ? { uri: process.env.API_BASE_URL + '/' + item.image } : defaultProductImage}
title={item.name}
>
<TextRegular numberOfLines={2}>{item.description}</TextRegular>
<TextSemiBold textStyle={styles.price}>{item.price.toFixed(2)}€</TextSemiBold>
{!item.availability &&
<TextRegular textStyle={styles.availability }>Not available</TextRegular>
}
<View style={styles.container1}>
<View style={{
alignItems: 'flex-start',
flex: 1,
textAlign: 'centre',
marginEnd: 10,
marginTop: 12,
padding: 0
}}>
<Pressable style={({ pressed }) => ({
backgroundColor: pressed
? 'rgb(255, 255, 255)'
: 'rgb(255, 173, 38)',
borderRadius: 20,
height: 40,
marginTop: 5,
marginBottom: 5,
padding: 20,
alignSelf: 'center',
flexDirection: 'row',
alignItems: 'center'
})} pressed={handleIncrement}>
<Text style={{ color: 'white', fontFamily: 'monospace', fontSize: 30 }}>+</Text>
</Pressable>
</View>
<View style={{
alignItems: 'flex-start',
flex: 1,
textAlign: 'centre',
marginEnd: 10,
marginTop: 12,
padding: 0
}}>
<Pressable style={({ pressed }) => ({
backgroundColor: pressed
? 'rgb(255, 255, 255)'
: 'rgb(255, 173, 38)',
borderRadius: 20,
height: 40,
marginTop: 5,
marginBottom: 5,
padding: 20,
alignSelf: 'center',
flexDirection: 'row',
alignItems: 'center',
textAlign: 'centre'
})} pressed= {handleDecrement}>
{
<Text style={{ color: 'white', fontFamily: 'monospace', fontSize: 35 }}>-</Text>
}
</Pressable>
</View>
<View style={{ textAlign: 'centre', marginTop: 25, marginLeft: 15 }}>
<Text style={{ color: 'grey' }}>{units}
</Text>
</View>
</View>
</ImageCard>
// aqui falta hacer que me devuelva la lista de objetos bien :(
)
}
const renderEmptyProductsList = () => {
return (
<TextRegular textStyle={styles.emptyList}>
This restaurant has no products yet.
</TextRegular>
)
}
const fetchRestaurantDetail = async () => {
try {
const fetchedRestaurant = await getDetail(route.params.id)
setRestaurant(fetchedRestaurant)
} catch (error) {
showMessage({
message: `There was an error while retrieving restaurant details (id ${route.params.id}). ${error}`,
type: 'error',
style: GlobalStyles.flashStyle,
titleStyle: GlobalStyles.flashTextStyle
})
}
}
return (
<Formik>
<FlatList
ListHeaderComponent={renderHeader}
ListEmptyComponent={renderEmptyProductsList}
style={styles.container}
data={restaurant.products}
extraData={units}
renderItem={renderProduct}
keyExtractor={item => item.id.toString()}
/>
</Formik>
)
}
I've tried several options such as the list of objects or separating into different components. However I wasn't able to perform it. It is expected to increment the quantity of the product when + is pressed and decremented when - is pressed. It receives an array of products which looks like this Array in the console
Here is a working example of what you need. Please adjust your code accordingly.
import React, { useState } from "react";
import { FlatList, Pressable, Text, View } from "react-native";
export default function App() {
const [productQuantities, setProductQuantities] = useState({});
const handleIncrement = (productId) => {
const updatedQuantities = { ...productQuantities };
if (updatedQuantities[productId]) {
updatedQuantities[productId]++;
} else {
updatedQuantities[productId] = 1;
}
setProductQuantities(updatedQuantities);
};
const handleDecrement = (productId) => {
const updatedQuantities = { ...productQuantities };
if (updatedQuantities[productId]) {
updatedQuantities[productId]--;
if (updatedQuantities[productId] === 0) {
delete updatedQuantities[productId];
}
setProductQuantities(updatedQuantities);
}
};
const renderProduct = ({ item }) => {
const productId = item.id.toString();
const units = productQuantities[productId] || 0;
return (
<View>
<Text>{item.name}</Text>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<Pressable
style={({ pressed }) => ({
backgroundColor: pressed ? "grey" : "blue",
borderRadius: 20,
height: 30,
width: 30,
justifyContent: "center",
alignItems: "center",
marginRight: 10
})}
onPress={() => handleDecrement(productId)}
>
<Text style={{ color: "white" }}>-</Text>
</Pressable>
<Text>{units}</Text>
<Pressable
style={({ pressed }) => ({
backgroundColor: pressed ? "grey" : "blue",
borderRadius: 20,
height: 30,
width: 30,
justifyContent: "center",
alignItems: "center",
marginLeft: 10
})}
onPress={() => handleIncrement(productId)}
>
<Text style={{ color: "white" }}>+</Text>
</Pressable>
</View>
</View>
);
};
const renderEmptyProductsList = () => {
return <Text>This restaurant has no products yet.</Text>;
};
const products = [
{ id: 1, name: "Pizza", price: 10.0 },
{ id: 2, name: "Pasta", price: 8.0 },
{ id: 3, name: "Salad", price: 6.0 }
];
return (
<FlatList
data={products}
renderItem={renderProduct}
ListEmptyComponent={renderEmptyProductsList}
keyExtractor={(item) => item.id.toString()}
/>
);
}
You may check it here: https://codesandbox.io/s/restaurant-card-rlezk1