6

I am trying to update a single key value pair in an array of objets using React.

Here is the setup

An array of objects

const array = [
  {id:1,name:'Tyler',age:23},
  {id:2,name:'Lauren',age:28},
  {id:3,name:'Nico',age:14},
]

Given an id and age, I want to be able to update the single object that matches the id. For example, given an id of 2 and age of 56, {id:2,name:'Lauren',age:28} should change to {id:2,name:'Lauren',age:56}

My approach

I've set up useState to copy the array of object. However, I am struggling to filter out for the selected id, change the age, and return the updated array.

This is what I currently have:

import { useState } from "react";

const array = [
  { id: 1, name: "Tyler", age: 23 },
  { id: 2, name: "Lauren", age: 28 },
  { id: 3, name: "Nico", age: 14 }
];

export default function App() {
  const [list, setList] = useState(array);

  const updateAge = (id = 2, age = 56) => {
    setList([...list, list.filter((item) => item.id === id)]);
  };

  return (
    <>
      <ul>
        {list.map((item) => {
          return (
            <li>
              {item.name} | {item.age}
            </li>
          );
        })}
      </ul>
      <button onClick={updateAge}>Update age</button>
    </>
  );
}

Here is my codesandbox link

Tyler Morales
  • 1,440
  • 2
  • 19
  • 56
  • 1
    Does this answer your question? [Whats the best way to update an object in an array in ReactJS?](https://stackoverflow.com/questions/28121272/whats-the-best-way-to-update-an-object-in-an-array-in-reactjs) – Emile Bergeron Feb 07 '22 at 17:13
  • If you want to delete an item from the array: [How to delete an item from state array?](https://stackoverflow.com/q/36326612/1218980) – Emile Bergeron Feb 07 '22 at 17:14
  • @EmileBergeron I'm trying to use hooks, not classes. It doesn't help that much. – Tyler Morales Feb 07 '22 at 17:16
  • Try using `map` instead. When the id matches, return a new object with updated age, otherwise return the same object that the map function was called with. – tromgy Feb 07 '22 at 17:17
  • Found a better duplicate target here: [How do I update states `onChange` in an array of object in React Hooks](https://stackoverflow.com/q/55987953/1218980). Notice how the solution is the same as classes (and the one you accepted as well)? – Emile Bergeron Feb 07 '22 at 18:22

3 Answers3

9

You can use the map function to produce a new array to set the state with.

const updateAge = (id, age) => {
    console.log(id, age);
    setList(
      list.map((item) => {
        if (item.id === id) {
          return { ...item, age };
        } else {
          return item;
        }
      })
    );
  };

If the id matches, it will merge the new age, otherwise it will return the item unchanged.

Note that it will only produce new objects for updated age, the rest will be the same references. That is to say it will be a new array, but most objects (except the changed one) will be the same. If you want new objects you can return { ...item } in the else clause as well.

In this particular case React will only be concerned that you set the state with new array.

Here's the sandbox

tromgy
  • 4,937
  • 3
  • 17
  • 18
  • 2
    I enjoy the simplicity of this solution. I've changed the if else statement to be a ternary operation for brevity. ````js setList( list.map((item) => { return item.id === id ? {...item, age} : item }) ) ```` – Tyler Morales Feb 07 '22 at 17:43
4
import  { useState } from "react";
const array = [
 { id: 1, name: "Tyler", age: 23 },
 { id: 2, name: "Lauren", age: 28 },
 { id: 3, name: "Nico", age: 14 }
];

export default function App() {
  const [list, setList] = useState(array);

  const updateAge = (id, age) => {
    // Find the item to update and store it in new list 
    let el = list.map((item) => {if(item.id === id){item.age=age}return 
     item});
    // Set the previous list to the new list
    setList(el)
    console.log(list)

 };

 return (
   <>
     <ul>
       {list.map((item, index) => {
          return (
           <li key={index}>
             {item.name} | {item.age}
           </li>
         );
        })}
      </ul>
      <button onClick={()=>updateAge(2, 56)}>Update age</button>
    </>
  );
}

Went to your codesandbox link changed it a bit does what you were trying to do now used Map instead of filter hope this helps

Ahmed Ali
  • 257
  • 1
  • 7
1

You can update you array like this

import { useState } from "react";
const array = [
  { id: 1, name: "Tyler", age: 23 },
  { id: 2, name: "Lauren", age: 28 },
  { id: 3, name: "Nico", age: 14 }
];

export default function App() {
  const [list, setList] = useState(array);

  const updateAge = (id = 2, age = 56) => {
    setList(list.map(l=>l.id==id?{...l,age:age}:l));
  };

  return (
    <>
      <ul>
        {list.map((item) => {
          return (
            <li>
              {item.name} | {item.age}
            </li>
          );
        })}
      </ul>
      <button onClick={updateAge}>Update age</button>
    </>
  );
}
JaivBhup
  • 792
  • 4
  • 7