I have a functional component that is a screen and I need to handle some state. I do not want to refactor my code to make it a class component and I would like to make use of hooks. I have a component within the screen that renders a flatlist (from JSON) of a product description, quantity and a box for a user input quantity. Currently my state for all the input quantities is tied together, so when I enter a number into 1 box, that same number is displayed in all boxes. How can I seperate and store the input state using hooks?
There is a lot of examples online with using hooks to store 1 peice of data but not multiple and as I do not know how many 'products' there will be a head of time I cannot create different useState's for them. Am I best having 1 useState for all the input boxes and stored in an array?
import { Text, View, StyleSheet, SafeAreaView, FlatList } from "react-native";
function InstallScreen({ navigation, route }) {
// State for the number installed component
const [quantityInstalled, setQuantityInstalled] = useState([]);
const { item } = route.params;
// pulling just the product arrays from the job data and storing separately
const productData = item.products;
return (
<View style={styles.containerNine}>
<View style={styles.descriptionBoxContainer}>
<View style={styles.descriptionBox}>
<FlatList
data={productData}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<DescriptionBox
productDescription={item.description}
dueQuantity={item.quantity}
value={quantityInstalled}
onChangeText={(value) => setQuantityInstalled(value)}
/>
)}
/>
<Text>Number installed is {quantityInstalled} </Text>
</View>
</View>
</View>
);
};
Description Component
import { View, Text, StyleSheet, TextInput } from "react-native";
const DescriptionBox = (props) => {
return (
<View style={styles.productsAllContainer}>
<View style={styles.descriptionBoxStyle}>
<Text style={styles.textStyle}>{props.productDescription}</Text>
</View>
<View style={styles.qtyBoxStyle}>
<Text style={styles.qtyTextStyle}>{props.dueQuantity}</Text>
</View>
<View>
<TextInput
style={styles.installedBoxStyle}
textAlign="center"
fontSize="18"
fontWeight="bold"
autoCapitalize="none"
autoCorrect={false}
keyboardType={"numeric"}
maxLength={5}
value={props.value}
onChangeText={props.onChangeText}
/>
</View>
</View>
);
};
Disclaimer: I have not used react native, but what I usually do is make the name, the id of the item in the list then pass that name up when changing the state
<input name={id} onChange={onChange} />
then having one call to use state but make the on change function get the name from the event handler
const [productQuantity, setProductQuantity] = React.useState('')
const onChange = (e) => {
const {name, value} = e.target;
setProductQuantity({...productQuantity,[name]:value})
};
however for your specific case you'd also probably need a function to get the installed quantity from the state, you could also pass down a function to the child to do this along the lines, of
const getProductQuantity = (id) => (
productQuantity[id] && productQuantity[id] || 0
)