skip to Main Content

Can someone explain to me why this is the accepted standard for adding to an object to the state in react as I can’t seem to find the answer I’m looking for.

const [artists, setArtists] = useState([]);

setArtists([
    ...artists,
    { id: nextId++, name: name }
]);

I feel like there should be a much easier way to do this other than artists.push() which the react docs say is bad as you should treat the state as immutable instead of having to combine the old state with the new.

Similar to how zustand state management works in the docs where it shows:

"The set function is to update state in the store. Because the state is immutable, it should have been like this:"

set((state) => ({ ...state, count: state.count + 1 }))

"However, as this is a common pattern, set actually merges state, and we can skip the …state part:"

set((state) => ({ count: state.count + 1 }))

Maybe I’m missing something, but could you explain a better/easier way for doing this or why this is the accepted standard and nothing easier can possibly exist?

2

Answers


  1. "Easier" is subjective, so its difficult to answer without also being subjective.

    Immer (https://immerjs.github.io/immer/update-patterns/) allows writing updates that feel more "natural" to a lot of developers. Immer is also used under the hood for Redux Toolkit.

    Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.
    , but Immer is typically more convenient.

    Taking your example:

    setArtists([
        ...artists,
        { id: nextId++, name: name }
    ]);
    

    In Immer, it would look like:

    setArtists(produce(draft => {
        draft.push({id: nextId++, name });
    }));
    
    Login or Signup to reply.
  2. React needs to check when a component needs to be updated, i.e. rendered.
    To do this, react compares the props and the state before and after the state update. Comparing whole objects is much more complex than simply assuming that objects don’t change. So if you want to change the state of an object and pass in a new object instead of the manipulated old object, react knows immediately that something needs to be re-rendered.

    In React, the state update function (e.g., setArtists in your example) replaces the current state with whatever you pass to it. It doesn’t merge the new state with the old state.

    This explicitness in state management gives you more control but also means you have to manually merge the previous state with the new state, which can be a bit verbose, especially when adding to an array or updating an object property.

    Other state management libraries provide a more straightforward merging mechanism because they are designed to handle complex state management and try to simplify these kinds of operations. But they add a layer of abstraction which might not always be necessary, especially for simpler apps. React prefers to give you the primitives and let you build your abstractions as you need them.

    Of course, you could also write your own hook that implements the operations appropriately, if necessary, to avoid the overhead in the individual components. For arrays it could look like this

    import { useState } from 'react';
    
    function useArray(initialArray) {
        const [array, setArray] = useState(initialArray);
    
        function push(element) {
            setArray(prev => [...prev, element]);
        }
    
        function remove(index) {
            setArray(prev => [...prev.slice(0, index), ...prev.slice(index + 1)]);
        }
    
        function clear() {
            setArray([]);
        }
    
        return { array, push, remove, clear };
    }
    
    export default useArray;
    
    

    to use it

    import useArray from './useArray';
    
    function App() {
        const artists = useArray([]);
        let nextId = 1;
    
        function addArtist(name) {
            artists.push({ id: nextId++, name: name });
        }
    
        
    }
    

    Maybe this workaround is more familiar to you, because it feels similar to the state handling and in my opinion it is more readable.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search