简体   繁体   中英

How to immutably update/replace React Redux State with a double nested array of objects?

My redux state has a SessionList which is an array of SessionObjects, and each SessionObject has an array of HandObjects.

I use state to update individual SessionObjects by adding new HandObjects, however I want to update the redux store with my updated SessionObject (immutably, if possible).

the index of the SessionObject within SessionList is action.payload.Id (I think? i will show my SessionObject constructor)

**Adding Sessions works just fine, and I only update a Session with the session already in the store

I have tried every link that I can find, but my code is just different enough that I can't seem to update my SessionList correctly.

my reducer, with the initial state store.js (where my reducers are)

const initialState = {
    SessionList: [],
}
...
case "UPDATE_SESSION":
            //action.payload is a SessionObject
            //action.payload.Id is the Id that i want to update
            // i want to set SessionList[action.payload.Id] = action.payload
            state = {
                ...state,
                SessionList : state.SessionList.map((item, index) => {
                    if (index != action.payload.id) {
                      return item
                    }

                    return action.payload
                    //This code doesn't visibly do anything that I can find
                  })

                // *******FIRST TRY*******
                // ...state,
                //  SessionList: {
                //     ...state.SessionList,
                //     SessionList[action.payload.id] : action.payload 
//syntax error, but basically what i want to do
                //      }
                // }
                // ***********************
            };
            break;

SessionObject constructor Session.js

export function SessionObject(_id, _name, _hands) {
    this.id = _id, //int
    this.name = _name, //string
    this.HandList = _hands //array of HandObject objects
}
var defaultSession = new SessionObject(0, "default", []);

*in case i am doing this wrong, I call (Session.js)

this.props.navigation.state.params.updateMethod(this.state.Session); //update store

from a stack-navigator child component.
then in the parent component, I call (Home.js)

UpdateSession = (session) => {
      this.props.updateSession(session);
    };

With my dispatcher looking like: (Home.js)

updateSession: (session) => {
        dispatch({
          type: "UPDATE_SESSION",
          payload: session
        });
      }

From testing, I am somewhat sure my reducer is getting called correctly.

I want to replace the SessionObject with action.payload in the correct index of the SessionList.

EDIT *

Session.js

addItem = () => {
        this.setState((state, props) => ({
        Session : {
          ...state,
          HandList: [...state.Session.HandList, new HandObject(state.HandCount)]
        },
        HandCount : state.HandCount + 1,
        }));
        this.props.navigation.state.params.updateMethod(this.state.Session); //update store
    };

The state in Session.js is a SessionObject

To achieve a result of SessionList[action.payload.Id] , you need to initialise SessionList as an object and not an array. Then you can update accordingly.

   const initialState = {
      SessionList: {},
   }

   case "UPDATE_SESSION":
            state = {
                ...state,
                SessionList: Object.keys(state.SessionList).reduce((acc, id) => {
                    if (id === action.payload.Id) {
                      acc[id] = action.payload;
                    } else {
                      acc[id] = state.SessionList[id];
                    }

                    return acc;
                  }, {});
            };

Update

As requested here , following are the add , update , replace and delete handlers without changing SessionList to an object.

const initialState = {
     SessionList: [],
}

Note: action.payload (wherever used) is a session object.

Add

state = {
    ...state,
    SessionList: [...state.SessionList, action.payload];
};

Update

state = {
    ...state,
    SessionList: state.SessionList.map((session) => {
        if (session.Id === action.payload.Id) {
           return Object.assign({}, session, action.payload);
        }

        return session;
    })
};

Replace

state = {
    ...state,
    SessionList: state.SessionList.map((session) => {
        if (session.Id === action.payload.Id) {
           return action.payload;
        }

        return session;
    })
};

Delete

state = {
    ...state,
    SessionList: state.SessionList.filter((session) => session.Id !== action.payload.Id)
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM