Home > other >  How to update an array of object inside another object in React
How to update an array of object inside another object in React

Time:01-20

I'm trying to update a single key/value pair in a user object which contains another array of object called "education". I set a custom attribute called "index" on the list components to access the array index when updating.

// User object
const [userData, setUserData]  = useState({
    firstName: '',
    lastName: '',
    title: '',
    email: '',
    phoneNumber: '',
    website: '',
    bio: '',
    education: [
      {
        id: uniqid(),
        school: '',
        degree: '',
        city: '',
        state: '',
        timeframe: ''

      }
    ]
})
// Render input form for Education
const listItems = props.userData.education.map((user, index) => {
    return (
      <div key={index}>
        <h2>University/School #{index}</h2>
        <input
          type="text"
          index={index}
          placeholder="Your school"
          name="school"
          onChange={props.handleChange}
          value={props.userData.education[index].school}
        />
      </div>
    );
  });

Created this fucntion handler for onChange but it just returns an empty string and doesn't update the object. I feel i'm using the spread operator here wrongly but can't figure out how to put all together rightly.

// Update user education state
const handleChange = (e) => {
  const { value, name } = e.target
  const index = e.target.getAttribute('index')
  setUserData(prevUser => ({
    ...prevUser,
    [prevUser.education[index]]: {
      [name]: value
    }
  }))
}

CodePudding user response:

You don't need to add a custom index value and get it off an attribute. You can add it to your change callback:

const listItems = props.userData.education.map((user, index) => {
    return (
      <div key={index}>
        <h2>University/School #{index}</h2>
        <input
          type="text"
          index={index}
          placeholder="Your school"
          name="school"
          onChange={(e) => props.handleChange(e, index)}
          value={props.userData.education[index].school}
        />
      </div>
    );
  });

if you run console.log inside your handleChange what do you see for value and name?

I am hoping you can learn a bit about how to debug your code.

const handleChange = (e, index) => {

  const { value, name } = e.target
  console.log({value});
  console.log({name});

  setUserData(prevUser => {
    const newItem = {
       [prevUser.education[index]]: {
          [name]: value
       }
    }
    console.log({newItem}); // is this what you expect?

    return ({
    ...prevUser,
    ...newItem,
    
  })))
}

Finally, your value should come from state directly, not Props. I am assuming your state is inside the same component as your rendering? Otherwise, are you passing state as a prop to your consuming component?

As for your spread, yes, you are missing a little.

const newItem = {
       [prevUser.education[index]]: {
         ...[prevUser.education[index]], // without this you will overwrite all the previous data
          [name]: value
       }
    }
  • Related