简体   繁体   中英

Redux reducer state mutations and restoring initial state

What's the best way to restore initial state? For this example let's say I can edit a car by dispatching the following actions:

dispatch(actions.editModel('Civic'));

dispatch(actions.editType({
    make: 'Ford',
    model: 'Focus'
}));

dispatch(actions.restoreInitialState());

My reducer looks like this:

const initialState = {
  id: '1',
  vehicle: 'car',
  type: {
    make: 'Honda',
    model: 'Accord'
  },
  license: 'abc'
}

export default createReducer({
  [actions.editType]: (state, payload) => ({
    ...state,
    type: payload // payload is an object
  }),
  [actions.editModel]: (state, payload) => ({
    ...state,
    type: {
      ...state.type,
      model: payload // payload is a string
    }
  }),
  [actions.restoreInitialState]: (state) => ({
    state: initialState // initial state has nested objects
  })
}, initialState)

Is there a risk I am mutating my state or restoring my initial state incorrectly? This might be overkill but I was thinking of editing my reducers like this:

export default createReducer({
  [actions.editType]: (state, payload) => ({
    ...state,
    type: { 
        ...payload // payload is an object
    }
  }),
  [actions.editModel]: (state, payload) => ({
    ...state,
    type: {
      ...state.type,
      model: payload // payload is a string
    }
  }),
  [actions.restoreInitialState]: (state) => ({
    state: {
        ...initialState // initial state has nested objects
    }
  })
}, initialState)

Is there a difference when I'm passing an object through the payload vs just referencing my initial state? (Plus my initial state contains nested objects)

You've got a great question. And to answer this, you need to think about why its so important to avoid mutating data in React. On every change in state - React does a shallow comparison of the updated virtual DOM with the old virtual DOM. And in this shallow comparison - when it comes across objects - it only checks the address of the object. So - as long as you have a new address for the parent - the DOM will update correctly.

Now, everytime you return from the reducer - as long as you are returning a new object with the updated state - return {... state} or an object with a different address - eg. return initialState - it's perfect. You don't need to worry about mutations. This is true even if you have a nested object within the state. As long as you change the address of the parent - the DOM will update correctly. So feel free to use the code like you did in the first case. You don't need to spread over the nested objects. Your payload will anyway have a different address.

The only thing to be weary about is doing something like this:

    case [actions.editModel]:
        const updatedState = state
        updatedState.model = payload;
        return updatedState;

In this case, the state object gets passed by reference to updatedState - that means both of them will share the same address. And since you're returning updatedState - the address hasn't changed and the DOM won't update correctly/consistently.

You can simply do this:

[actions.restoreInitialState]: () => initialState;

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