Duck

An example of /store/redux/app.js following re-duck style

Define `createReducer` helper

const createReducer = (initialState = {}, handlers = {}) => (state, action) => {
  const nextState = produce(state, draft => {
    if (handlers[action.type]) {
      return handlers[action.type](draft, action)
    }
  })

  return nextState
}

produce is a function of immer

Declare initial state

const initialState = {
  locale: 'en',
  theme: 'light',
}

Declare action types

const types = new Proxy({
  CHANGE_LOCALE: 'CHANGE_LOCALE',
  CHANGE_THEME: 'CHANGE_THEME',
}, {
  get: (target, prop) => `app_name/domain_namespace/${target[prop]}`,
})

prefix app_name/domain_namespace for separating your action from 3rd parties actions such as connected-react-router, redux-saga when working with redux devtools

Declare action creators

const actions = {
  changeLocale: newLocale => ({ type: types.CHANGE_LOCALE, payload: newLocale }),
  changeTheme: newTheme => ({ type: types.CHANGE_THEME, payload: newTheme }),
}

Declare reducer

const reducer = createReducer(initialState, {
  [types.CHANGE_LOCALE]: (draft, { payload }) => {
    draft.locale = payload
  },
  [types.CHANGE_THEME]: (draft, { payload }) => {
    draft.theme = payload
  },
})

Declare selectors

const selectors = {
  selectApp: state => state.app || initialState,
  makeSelectLocale() {
    return createSelector(this.selectApp, ({ locale }) => locale)
  },
  makeSelectTheme() {
    return createSelector(this.selectApp, ({ theme }) => theme)
  },
}

createSelector is a function of reselect

Last updated