Search code examples
arraysreactjsstatedispatchpayload

Update react state without overriding previous state


I am trying to update a state value w/ a multidimensional array but I can't seem to figure how to update one of the arrays object key values without effecting the previous state value which I use later in the process after the dispatch call. I the code below the payload carries an array of ids (nodes) that I loop through and change the only those objects within the state object. Rather straight forward, but updating a multidimensional array of objects and not effecting the state has me confused.


    UPDATE_RESTRICTION: (curState, payload) => {
    
      const updatedNodes = {...curState.layout}
      const accessProfile = BpUAE.accessProfileID
    
      payload.nodes.forEach((node, index) => {
    
    
        if (typeof (updatedNodes[node].settings.bp_uae_restrictions) === 'undefined') {
          updatedNodes[node].settings.bp_uae_restrictions = {};
        }
    
        if (typeof (updatedNodes[node].settings.bp_uae_restrictions[accessProfile]) === 'undefined') {
          updatedNodes[node].settings.bp_uae_restrictions[accessProfile] = {};
        }
    
    
        updatedNodes[node].settings.bp_uae_restrictions[accessProfile].is_node_restricted =  JSON.parse(payload.isRestricted);

       })

    
      return {layout: updatedNodes}
    
    
    }

Please let me know if you need more information and thanks for any help you can provide.


Solution

  • You are not applying immutable update pattern correctly, you are mutating the nested references pointing into the current state object. You need to create new object references and shallow copy all state that is being updated.

    UPDATE_RESTRICTION: (curState, payload) => {
      const updatedNodes = { ...curState.layout }
      const accessProfile = BpUAE.accessProfileID;
    
      payload.nodes.forEach((node, index) => {
        if (typeof (updatedNodes[node].settings.bp_uae_restrictions) === 'undefined') {
          updatedNodes[node] = {
            ...updatedNodes[node],
            settings: {
              ...updatedNodes[node].settings,
              bp_uae_restrictions: {},
            },
          };
        }
    
        if (typeof (updatedNodes[node].settings.bp_uae_restrictions[accessProfile]) === 'undefined') {
          updatedNodes[node] = {
            ...updatedNodes[node],
            settings: {
              ...updatedNodes[node].settings,
              bp_uae_restrictions: {
                ...updatedNodes[node].settings.bp_uae_restrictions,
                [accessProfile]: {},
              },
            },
          };
        }
    
        // now all the new references have been created and previous
        // state shallow copied, you can update the deeply nested 
        // `is_node_restricted` property.
        updatedNodes[node].settings.bp_uae_restrictions[accessProfile].is_node_restricted = JSON.parse(payload.isRestricted);
      });
    
      return {
        ...curState,
        layout: updatedNodes,
      };
    }
    

    UPDATE: Added the last immutable pattern

      const updatedNodes = { ...curState.layout }
      const accessProfile = BpUAE.accessProfileID;
    
      payload.nodes.forEach((node, index) => {
        if (typeof (updatedNodes[node].settings.bp_uae_restrictions) === 'undefined') {
          updatedNodes[node] = {
            ...updatedNodes[node],
            settings: {
              ...updatedNodes[node].settings,
              bp_uae_restrictions: {},
            },
          };
        }
    
        if (typeof (updatedNodes[node].settings.bp_uae_restrictions[accessProfile]) === 'undefined') {
          updatedNodes[node] = {
            ...updatedNodes[node],
            settings: {
              ...updatedNodes[node].settings,
              bp_uae_restrictions: {
                ...updatedNodes[node].settings.bp_uae_restrictions,
                [accessProfile]: {},
              },
            },
          };
        }
    
        // now all the new references have been created and previous
        // state shallow copied, you can update the deeply nested 
        // `is_node_restricted` property.
        updatedNodes[node] = {
          ...updatedNodes[node],
          settings: {
            ...updatedNodes[node].settings,
            bp_uae_restrictions: {
              ...updatedNodes[node].settings.bp_uae_restrictions,
              [accessProfile]: {
                ...updatedNodes[node].settings.bp_uae_restrictions[accessProfile],
                is_node_restricted:  JSON.parse(payload.isRestricted)
              },
            },
          },
        };
      });
    
      return {
        ...curState,
        layout: updatedNodes,
      };
    }```