skip to Main Content

I have a below function which takes in a response and transforms/adds properties to a response object for my UI and the transformed response is again returned.

So the way it works is initially the method is called with no existing data and it works fine.
However when I do result = data;…where data is actually existing data that was saved to Redux state and then when mutations are run on that existing data. At that point, I get the issue (TypeError: Cannot assign to read only property ‘secGroupOrder’ of object ‘#’ ) after having the transformed response go through Redux Toolkit states. So the error does not come for the first run, but for subsequent runs. This error is even after setting writable to true on all the properties. Not sure what can I do to fix this ?

Below is my function

function formatData(initialResponse, existing) {
    let response = {};
    
    Object.defineProperties(response, {
      secGroupOrder: {writable: true},
      secGroups: {writable: true},
      sections: {writable: true},
      fields: {writable: true}
    });

    if (existing) {
        response = existing;
        let newOrder = copySecGroupOrder(secGroupOrder);
        newOrder.forEach(group => {
            let existingGroup = existing.secGroups[group.name];
            if (existingGroup && existingGroup.sections) {
                group.sections = existingGroup.sections;
            }
        });
        response.secGroupOrder = newOrder;
        //response = Object.assign({}, response , secGroupOrder, newOrder); // Commented above and replaced since it was giving "Cannot assign to read only property" error
    } else {
        response = {
            secGroupOrder: copySecGroupOrder(secGroupOrder),
            secGroups: {},
            sections: sections,
            fields: copyFields(fields)
        };
    }

    response.secGroupOrder.forEach(group => { 
        response.secGroups[group.name] = group;
        if (!group.sections) {
            group.sections = {};
        }
    });

    if( response.secGroups['Comp 1']){
        response.secGroups['Comp 1'].component = Cmp1;
    }
    if (response.secGroups['Comp 2']) {
        response.secGroups['Comp 2'].component = Cmp2;
    }
    
    return response;
}

3

Answers


  1. Your code here is directly modifying your Redux Toolkit state, but outside of a reducer.

    You are not creating "copies" by doing response = existing; – it’s just another variable name pointing to the state you have in Redux – and Redux state is not allowed to be modified.

    So, your line

     response.secGroupOrder = newOrder;
    

    is equal to

     state.secGroupOrder = newOrder;
    

    If you want to directly modify those values, you have to make sure to make a deep copy first.

    Login or Signup to reply.
  2. I think you’re facing this issue because you’re trying to change the data stored in your store’s state directly without going through a reducer, look into shallow and deep copies in javascript.
    Essentially your issue can be solved if you make a deep copy of your object, since making changes to the deep copy will not cause store to throw you an error

    // if item is the old data from redux/toolkit
    const newData = JSON.parse(JSON.stringify(oldData));
    // keep in mind each deep copying method has its limitations and you should use the one best suited to your object's structure.
    

    I would recommend using reducers to make any changes to existing states, that is the preferred approach. If for some reason you don’t wish to do that and only use reducers to do a simple

    reducer(state, action){
    state.data = action.payload
    }
    

    and not do anything else in reducer (though would recommend making any changes you do in a reducer), you can make a deep copy, and pass it to the reducer after you’re done.

    You can look into deep and shallow copies here.
    https://www.freecodecamp.org/news/copying-stuff-in-javascript-how-to-differentiate-between-deep-and-shallow-copies-b6d8c1ef09cd/

    Login or Signup to reply.
  3. Make a deep copy of existing with structuredClone to avoid modifying it:

    response = structuredClone(existing);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search