1

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

7
  • Where are you creating the session provided to updateSession? There's a possibility that you're passing the same reference over and over? I.e., if you try with ``` payload: { ...session } ``` the issue persists? Commented Jun 11, 2019 at 2:41
  • @sminutoli I added the code in my question, where I am updating a Session. I thought that the way I do it would create a new object? In terms of my workflow, my home screen accesses the redux store, and places the SessionList (full of SessionObjects) in a FlatList. Each of these is a button, which navigates to a Session page, which shows a singular SessionObject's list of HandObjects in the same way. The Hands are added/updated, which updates the SessionObject in the state of Session.js, which sends the session back to the Home screen, updating the redux store with the complete structure. Commented Jun 11, 2019 at 3:13
  • setState isn't a synchronous call, you can't use this.state.Session expecting it being the brand new object, maybe you could store this new session on a variable, passing both setState and updateMethod the same object. I'm not understanding why you mix redux w setState anyway. Commented Jun 11, 2019 at 3:22
  • The SessionObject constructor uses a lowercase "i" for its id property, while in the UPDATE_SESSION case of the reducer, action.payload.Id (uppercase "I") is written, which would evaluate as undefined. Is that what you're seeing if you log action.payload? Commented Jun 11, 2019 at 3:47
  • @leitdeux good catch, however that didn't change the result Commented Jun 11, 2019 at 3:56

1 Answer 1

4

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)
};
Sign up to request clarification or add additional context in comments.

6 Comments

Objects dont have .reduce, I understand your intent but its innacurate
@sminutoli You are right. I am habitual of using lodash.reduce that also works on objects. Please see updated answer.
@UmairSarfraz is there a way to do this with an array? My structure doesn't work with a SessionList object. The SessionList holds an array of SessionObjects, which each hold an array of HandObjects. I need to be able to add/delete/update/replace each respective object in all levels of my structure
@AdamWells Yes. I have updated my answer. Please check. Hope that answers your question. If you need any clarification, please feel free to let me know.
@UmairSarfraz That is very helpful thank you! However I am starting to think that my problem might be elsewhere in my app. In my Session.js file, I am creating HandObjects which are supposed to be added to the SessionObject in it's Hands array, and when i navigate back to the SessionList in Home.js, and then navigate back to the Session.js file, the HandObjects that I created beforehand should still be there, however it deletes them.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.