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

Time:11-25

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!

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