'Storing React form data in a nested object with useState

I'm building out a form with React, and I want to store the form fields in an object with nested data like this:

{
  name: "Test User",
  email: "[email protected]",
  address: {
    street: "123 Main St",
    city: "New York",
    state: "NY"
  }
}

The nested address is what I'm having trouble with.

My code looks like this:

const [booking, setBooking] = React.useState({ address: {} });

  const handleChange = e => {
    const { name, value } = e.target;
    setBooking(prevState => ({
        ...prevState,
        [name]: value
    }));
  };

return (
  <form onSubmit={handleSubmit}>
    <label>Name</label><input type="text" name="name" value={booking.name} onChange={handleChange} />
    <label>Email</label><input type="text" name="email" value={booking.email} onChange={handleChange} />
    <label>Street Address</label><input type="text" name="address.street" value={booking.address.street} onChange={handleChange} />
    <label>City</label><input type="text" name="address.city" value={booking.address.city} onChange={handleChange} />
    <label>State</label><input type="text" name="address.state" value={booking.address.state} onChange={handleChange} />
    <button type="submit">Create booking</button><br /><br />
  </form>
)

But with this approach, the address values are not being nested. For example, for the street address field, the booking ends up with a key of address.street rather than using the nested address object.

How can I get the form data to be stored in a nested object?



Solution 1:[1]

you need to create two onchange events function one for booking and another for address

  const [booking, setBooking] = React.useState([]);
  const [addressDetails, setAddressDetails] = useState([])
  function handleChange(e) {
    setBooking(prevState => ({
      ...prevState,
    
      ...prevState.raw,
      [e.target.name]: e.target.value,}
    ))
  }

function handleChangeAddress(e) {

  setAddressDetails(prevState => ({
  ...prevState,
  Address: {
    ...prevState.Address,
    [e.target.name]: e.target.value,
  },
}))

  setBooking(prevState => ({
  ...prevState,
  ...prevState.store,
  Address:addressDetails.Address
  
}))

}

Solution 2:[2]

For the address you can create a separate handler function, i'm using typescript to explain but you can do the same in Javascript too( just remove types of e from function parameter)

const onAddressHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
  setBooking({
    ...booking, 
    address:{
    ...booking.address,
    [e.target.name]: e.target.value
  },
  });
};

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Nivethan