I'm trying to modify a nested property of a useState, but I'm struggling to do it in this case:
The component receives a prop "order" which has many items (line_items), which are the products within that order
A useEffect iterates through the line_items and generates an array which is stored in an "editOrders" state
useEffect(() => { if (order.line_items && order.line_items.length) { setEditOrders([]);
order.line_items.forEach(item => { setEditOrders(prevState => [ ...prevState, { name: item.name, price: item.total, quantity: item.quantity, weight: '' } ]) }) } }, [])
The items in the array state "editOrders" is displayed in a form
<form onSubmit={(e) => handleSubmitChanges(e)}> { (editOrders.map((item, index) => ( <div style={{ display: "flex", flexDirection: "row", padding: "10px 30px", alignItems: "center" }}> <h5 style={{flex: 8}}>{item.name}</h5> <MDBox pt={2} pb={1} px={1} sx={{flex: 3}}> <MDInput type="text" variant="standard" label="Gewicht" disabled={loading && true} onChange={(e) => setEditOrders(e.target.value)} value={item.weight} /> </MDBox> /////// THIS IS WHERE THE PROBLEM IS <MDBox pt={2} pb={1} px={1} sx={{flex: 1}}> <FormControl variant="standard"> <Select value="kg" style={{height: 44}} label="Einheit" endAdornment={ <InputAdornment position="end"> <ArrowDropDown fontSize="medium" color="standard"/> </InputAdornment> } onChange={(e) => setEditOrders(prevState => ({ ...prevState, editOrders[index].weight: e.target.value }))} disabled={loading && true} > <MenuItem value="g">g</MenuItem> <MenuItem value="kg">kg</MenuItem> <MenuItem value="ml">ml</MenuItem> <MenuItem value="cl">cl</MenuItem> <MenuItem value="l">l</MenuItem> <MenuItem value="Stück">Stück</MenuItem> </Select> </FormControl> </MDBox> </div> ))) } <MDBox pt={2} pb={3} px={3}> <MDButton type="submit" variant="gradient" color="info" disabled={disabled}> "Create" </MDButton> </MDBox> </form>
Since it's a dynamically generated list, depending on the {order} prop, my goal is to change the state of that particular item in the list.
Thank you!
CodePudding user response:
Well you can do this by writing a function that gets the index and the value and updating the state like this:
const handleOnChange = (event, index) => {
setEditOrders((prevState) => {
const newState = [...prevState];
newState[index].weight = event.target.value;
return newState;
)
)
And then use it like this:
<MDBox pt={2} pb={1} px={1} sx={{flex: 1}}>
<FormControl variant="standard">
<Select
value="kg"
style={{height: 44}}
label="Einheit"
endAdornment={
<InputAdornment position="end">
<ArrowDropDown fontSize="medium" color="standard"/>
</InputAdornment>
}
onChange={(event) => handleOnChange(event, index)}
disabled={loading && true}
>
<MenuItem value="g">g</MenuItem>
<MenuItem value="kg">kg</MenuItem>
<MenuItem value="ml">ml</MenuItem>
<MenuItem value="cl">cl</MenuItem>
<MenuItem value="l">l</MenuItem>
<MenuItem value="Stück">Stück</MenuItem>
</Select>
</FormControl>
</MDBox>
CodePudding user response:
You first duplicate the array, then you can safely mutate the new array.
onChange={(e) => setEditOrders(prevState => ({
const prevOrder = prevState[index];
const nextState = [...prevState];
nextState[index] = { ...prevOrder, weight: e.target.value };
return nextState;
}))}