Mohammad Zuha Khalid
Mohammad Zuha Khalid

Reputation: 87

Update values inside array of objects using Hooks

I am trying to add meeting events using Google Calendar API. In that I want to update my email in below ela object using hooks I mean to say that I want to update my email [email protected] 'attendees': [ {'email': '[email protected]'},] every time I take input using given form.

    function App() {
      var ela={
        'attendees': [ 
          {'email': '[email protected]'},
          {'email': '[email protected]'}
        ]
      }
      const [formDB,setFormDB]=useState(ela);
         
      const handleClick = (e) => {
        e.preventDefault();
        gapi.load('client:auth2', () => {
          console.log('loaded client')
    
          gapi.client.load('calendar', 'v3', () => console.log('bam!'))
    
          gapi.auth2.getAuthInstance().signIn()
          .then(() => {
            
           // var event=formDB;
            console.log(formDB);
            var request = gapi.client.calendar.events.insert({
              'calendarId': 'primary',
              'resource': formDB,
            })
    
              request.execute(formDB => {
              console.log(formDB)
              window.open(formDB.htmlLink)
            })}
    
    
      return (
        <div className="App">
         // I need to fix this onChange eventin following input. Everytime I am trying to change using below logic it's saying 
         <input
            type="email"
            name="formDB.attendees[0].email"
            value={formDB.attendees[0].email}
            onChange={e=>setFormDB({ ...formDB.attendees[0], email: e.target.value})}  **fix this**
          />
         <input type="submit" name="Confirm" />
        </form>
         </div>
      );
    }

enter image description here

Upvotes: 0

Views: 39

Answers (1)

Drew Reese
Drew Reese

Reputation: 202667

Issue - State Shape Mutation

setFormDB({ ...formDB.attendees[0], email: e.target.value})

You are mutating the state shape from

{ attendees: [] }

to

{ email: string }

There is no longer a formDB.attendees array, so attempting to access formDB.attendees[0] throws an error since formDB.attendees is undefined.

Solution - Maintain the State Invariant

It seems you are attempting to update the first email in the array. When updating values in arrays in react state you need to shallow copy the entire array, and then update the index/element. In fact, when updating any nested state you need to shallow copy any nested objects your are updating.

<input
  type="email"
  name="formDB.attendees[0].email"
  value={formDB.attendees[0].email}
  onChange={e => setFormDB({
    ...formDB,
    attendees: formDB.attendees.map((el, i) => i === 0 ? { email: e.target.value } : el)
  })}
/>

Alternatively since you are always updating the first email you can create a new array, replacing the first element and slice in the rest of attendees array.

<input
  type="email"
  name="formDB.attendees[0].email"
  value={formDB.attendees[0].email}
  onChange={e => setFormDB({
    ...formDB,
    attendees: [{ email: e.target.value }, ...formDB.attendees.slice(1)],
  })}
/>

Upvotes: 1

Related Questions