DEV Community

Rishabh Jain
Rishabh Jain

Posted on • Edited on

How to update an array state in React.Js

Ever tried to update an array in the React and ended up mutating the existing state?
Then you might be wondering why your component didn't update. Well you are not alone i did that too, and turns out a lot of other people face the exact same issue.

Let's learn the correct way to do it today...

Let's take an example of a list.

  • We will allow addition of a new items to the list.
  • Deletion of an item.
  • Adding an item at a specific point in an array.

Addition of an element.


// Method 1 -> Use array destructure
const addUser = () => {
  const newUser = {
    id: Date.now(),
    username: `User ${users.length + 1}`
  };
  const newUsers = [...users, newUser];

  setUsers(newUsers);
};

// Method 2 -> Use slice method with combination of push method.
const addUser = () => {
  const newUser = {
    id: Date.now(),
    username: `User ${users.length + 1}`
  };

  const newUsers = users.slice();
  newUsers.push(newUser);

  setUsers(newUsers);
};
Enter fullscreen mode Exit fullscreen mode

With method one we are simply using ES6 array destructing and appending an element to it. Where as method 2 goes old school using slice and push methods.

Deletion of an element.


// Method 1 -> Use array destructure
const removeUser = (index) => () => {
    const newUsers = [...users];
    newUsers.splice(index, 1);

    setUsers(newUsers);
  };

// Method 2 -> Use slice method.
const removeUser = (index) => () => {
    const newUsers = users.slice();
    newUsers.splice(index, 1);

    setUsers(newUsers);
  };

Enter fullscreen mode Exit fullscreen mode

With method one we are simply using ES6 array destructing to shallow clone the array and then mutating the new array by deleting the element. With method 2 we are using slice to shallow clone the array.

Addition of an element at a specific index.


  // Method 1 -> Use array destrcture.
  const addAfter = (index) => () => {
    const newUser = {
      id: Date.now(),
      username: `User ${users.length + 1}`
    };

    const newUsers = [
      ...users.slice(0, index + 1),
      newUser,
      ...users.slice(index + 1)
    ];

    setUsers(newUsers);
  };

    // Method 2 -> Using splice
  const addAfter = (index) => () => {
    const newUser = {
      id: Date.now(),
      username: `User ${users.length + 1}`
    };
    const newUsers = [...users]; 
    newUsers.splice(index + 1, 0, newUser)

    setUsers(newUsers);
  };
Enter fullscreen mode Exit fullscreen mode

With method one we are using slice , slice(start, length) we grab all the elements till the given index. After that we append the new element, lastly using slice(index + 1) we are taking the remaining items from the original array and concentrate everything using ES6 array destructing.

Method 2 we are taking advantage of a quirk that comes with array [splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) with splice we can push the elements in array as well using its 3rd argument.

Full Code [https://codesandbox.io/s/objective-rgb-4z4yz?file=/src/App.js]

import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const [users, setUsers] = useState([
    { id: Date.now() + 1, username: "User 1" },
    { id: Date.now() + 2, username: "User 2" }
  ]);

  const addUser = () => {
    const newUser = {
      id: Date.now(),
      username: `User ${users.length + 1}`
    };
    // Method 1 -> Use array destructure
    const newUsers = [...users, newUser];

    // Method 2 -> Use slice method with combination of push method.
    // const newUsers = users.slice();
    // newUsers.push(newUser);

    setUsers(newUsers);
  };

  const removeUser = (index) => () => {
    // Method 1 -> Use array destrcture.
    const newUsers = [...users];
    newUsers.splice(index, 1);

    // Method 2 -> Use slice method.
    // const newUsers = users.slice();
    // newUsers.splice(index, 1);

    setUsers(newUsers);
  };

  const addAfter = (index) => () => {
    const newUser = {
      id: Date.now(),
      username: `User ${users.length + 1}`
    };
    // Method 1 -> Use array destrcture.
    // const newUsers = [
    //   ...users.slice(0, index + 1),
    //   newUser,
    //   ...users.slice(index + 1)
    // ];

    // Method 2 -> Using splice
    const newUsers = [...users]; 
    newUsers.splice(index + 1, 0, newUser)

    setUsers(newUsers);
  };

  return (
    <>
      <button onClick={addUser}>Add User</button>
      {users.map((user, index) => (
        <div className="user" key={user.id}>
          {user.username}
          <button onClick={removeUser(index)}>Remove User</button>
          <button onClick={addAfter(index)}>Add immediate next User</button>
        </div>
      ))}
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Top comments (7)

Collapse
 
hgaleh profile image
Hojjat Bakhtiyari • Edited

You can use map and Object.assign too!

Collapse
 
jrishabh55 profile image
Rishabh Jain • Edited

Can you put more context here?,
if we are talking about Map data type, then that's a different process to handle it.
If it's about the map function in the Array prototype, i agree we get a new array in return but that is a relatively expensive operation.

For object assign, that's of objects only right?, We can apply them for arrays. I'm planning a follow up article for object state change as well.

Collapse
 
hgaleh profile image
Hojjat Bakhtiyari

map function of array is a simple way to exclude an element from array and make a new array.
You can use Object.assign to make new array. I do this hack:
clonedArray = Object.assign([], toBeClonedArray);

Thread Thread
 
jrishabh55 profile image
Rishabh Jain

okey, so,

  1. i think what you are talking about is filter function not map on the array, yes we can use filter to remove an item from the array for sure. and that works its a relative expensive operation tho, because JS have to loop over the entire array.
    With map, you can create a new array but can't really remove an item in a straightforward manner.

  2. Thanks for the Object.assign() thing, i didn't realize we can use it for arrays too, Good to know

Thread Thread
 
hgaleh profile image
Hojjat Bakhtiyari

Thank you for talking about time complexity of those methods.

You can use flatMap too
s.flatMap(x => (x === 10) ? [] : x) === s

Thread Thread
 
hgaleh profile image
Hojjat Bakhtiyari

It is hard to use slice to remove an element, isn't it?

Thread Thread
 
jrishabh55 profile image
Rishabh Jain

Yeah flatMap is an option, but isn't that unnecessary ?, i mean we can use filter if we just wanna iterate over the full array.

arr.filter(it => it !== 1)

Whenever the condition returns true that item is added to the return array, and when the condition returns false it is not added to the new array. i wouldn't recommend this approach tho, same reason no need to iterate over the full array just to remove an item. Much better to use findIndex and splice combination if you don't have the index of which item to remove. with findIndex we will only iterate over an array upto the point we find the requested item.

You can't really remove an array using slice, we can do it with splice tho, it's fairly simple developer.mozilla.org/en-US/docs/W...

arr.splice(start, length) problem with react and splice is that it mutates the existing array and with react we don't wanna mutate the original state so we make a copy array first.