简体   繁体   中英

How do I edit nested state of dynamicly generated state (using useState hook)?

I'm trying to modify a nested property of a useState, but I'm struggling to do it in this case:

  1. The component receives a prop "order" which has many items (line_items), which are the products within that order

  2. 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: '' } ]) }) } }, [])
  3. 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!

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>

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;
}))}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM