Glenncito
Glenncito

Reputation: 930

Unable to access the initialState of a slice in Redux, so I'm having to resort to manually setting the state properties

I have a slice called modal which is responsible for showing and hiding a modal, using actions showModal and hideModal.

Here is what it looks like:

    export const modal = createSlice({
  slice: "modal",
  initialState: {
      visible: false,
      selectedExpenseId: null
  },
  reducers:{
    showModal: (state, { payload }) => (
      state = {
        visible: true,
        selectedExpenseId: payload
      }
    ), 
    hideModal: (state, {payload}) => (state = state.initialState) 
    //hideModal: (state, {payload}) => (state = {visible: false, selectedExpenseId: null}) 

  }
});

showModal works as intended, but when I call hideModal nothing happens, as it seems I am unable to access initialState in this manner. When I resort to the commented out line which manually assigns the values in the intended way, it works.

I would like to know what I am doing wrong, as I would obviously prefer to be accessing initialState properly. I am new to React and redux, so I'm sure that I'm probably just missing something obvious here.

Cheers.

Upvotes: 0

Views: 1492

Answers (2)

markerikson
markerikson

Reputation: 67539

Both your reducers are currently wrong. You're seeing "correct" behavior for showModal only by accident.

It looks like you're using Redux Starter Kit. Since that uses Immer inside, there are two ways you can update the state:

  1. "Mutate" the contents inside the state value
  2. Create a new immutably-updated value yourself, and return it.

Neither of your reducers are actually doing that correctly.

Assigning state = something inside of a reducer does not mutate the contents of state, and it is not returning a new value. Instead, it's just changing what the local variable state in this function is pointing to.

In addition, there is no state.initialState field.

If showModal is working, it's only by accident, possibly because the assignment statement is also implicitly returning the result of the assignment.

What you should be doing is something like this:

const initialState = {
    visible: false,
    selectedExpenseId: null
};

export const modal = createSlice({
    slice: "modal",
    initialState,
    reducers: {
        showModal(state, {payload}) {
            return {visible: true, selectedExpenseId: payload};
        },
        hideModal(state) {
            return initialState;
        }
    }
});

Note that you could also have written the reducers like:

showModal(state, {payload}) {
    state.visible = true;
    state.selectedExpenseId = payload;
}

(Source: I'm a Redux maintainer, and I wrote Redux Starter Kit.)

Upvotes: 1

Salim Khan
Salim Khan

Reputation: 104

Nowhere in the documentation of Redux is mentioned that you will receive a property in the state named initialState which will be containing the initial state.

Redux does not populate any property in the state object by itself unless you do it in your reducers or via initialState. There are various ways in which you can achieve the desired behaviour out of which you mentioned 1 in the question itself. If you want to access it via initialState, then you can follow the below logic:

const initialState = {
  visible: false,
  selectedExpenseId: null
};
export const modal = createSlice({
  slice: "modal",
  initialState: {...initialState},
  reducers:{
    showModal: (state, { payload }) => (
      state = {
        visible: true,
        selectedExpenseId: payload
      }
    ), 
    hideModal: (state, {payload}) => (state = {...initialState}) 
  }
});

We have used spread notation (triple dot {...}) to avoid the mutation of the original initialState object.

Upvotes: 0

Related Questions