Updating state with React and Websockets I'm working on a React app with websocket. In this app there is a socket event listener which returns 3 types: add, change, and remove. Certain state update operations will be performed based on the type received.

Do I properly mutate the users state? I'm not sure whether it follows the principle of React regarding updating states.

ws.on("connect", () =&gt; {
  console.log("connected");

  ws.emit("load");
});

ws.on("feed", response =&gt; {
  const prev = response.old_val;
  const next = response.new_val;
  const type = response.type;
  setUsers(users =&gt; {
    let currentUser = [...users];
    let index;
    switch (type) {
      case "add":
        return [...users, next];
      case "change":
        index = users.findIndex(u =&gt; u.id === next.id);
        currentUser[index].name = next.name;
        return currentUser;
      case "remove":
        index = users.findIndex(u =&gt; u.id === prev.id);
        currentUser.splice(index, 1);
        return currentUser;
      default:
        return currentUser;
    }
  });
});
This seems reasonable. The most important part is that you do not mutate the react state in-place. By doing let currentUser = [...users]; you copy the state and instead mutate the copy, then assign it as the updated state.

An alternative would be to use .map and .filter to make your changes. I see this pattern more often than the state copy approach.

Example:

ws.on("feed", response =&gt; {
  const { new_val: next, type } = response; // Use destructuring and inline renaming.

  setUsers(users =&gt; {
    switch (type) {
      case "add":
        return [...users, next];

      case "change":
        return users.map(u =&gt; {
          // Only change the user specified in the message
          if (u.id === next.id) return {...u, name: next.name } 
          return u;
          // or return users.map(u =&gt; u.id !== next.id ? u : ({...u, name: next.name})) if you prefer one-liners
        })

      case "remove":
        return users.filter(u =&gt; u.id !== next.id);

      default:
        return users;
    }
  });
});