Idiomatic Redux store updates

@tlvince

2017-08-18

Rationale

Update store slice

const updateShipmentReducer = (state, action) => {
  const parentDocId = action.shipment.parentDocId
  const { [parentDocId]: omit, ...nextState } = state
  return {
    ...nextState,
    [action.shipment.snapshotId]: {
      ...action.shipment
    }
  }
}

Computed properties

const { [parentDocId]: ... }

ES2015 computed property names

AKA dynamic object keys

const parentDocId = 'foo'
const obj = {
  [parentDocId + 'Bar']: 'baz'
}
obj
//=> { fooBar: 'baz' }

Object destructuring

const { [parentDocId], ... } = state

ES2015 object destructuring

Assigns new variables from object properties

const props = { id: '1', name: 'bahmutov' }
const { id, name } = props
//=> const id = '1'; const name = 'bahmutov'

Object rest/spread

const { ...nextState } = state

Object spread

Shallow-clones objects via:

const nextState = Object.assign({}, state)

Not yet formalised in ES spec!

Recap

const updateShipmentReducer = (state, action) => {
  const parentDocId = action.shipment.parentDocId
  const { [parentDocId]: omit, ...nextState } = state
  return {
    ...nextState,
    [action.shipment.snapshotId]: {
      ...action.shipment
    }
  }
}

Why?

  • shipments indexed by ID in shipments slice
    • see: normalising state shape
  • shipment has just been modified
    • e.g. api.saveChanges to update batch quantities
  • Need to update store slice immutably

Result

state was updated immutably with the parent shipment key omitted

const state = { shipmentA: {}, shipmentB: {} }
const parentDocId = 'shipmentA'
const { [parentDocId]: omit, ...nextState } = state
nextState
//=> { shipmentB: {}}

Check with Babel REPL

Actual update

const parentDocId = action.shipment.parentDocId
return {
  // Spread
  ...nextState,
  [action.shipment.snapshotId]: {
    // Spread
    ...action.shipment
  }
}

Fin!

References

// reveal.js plugins