Доступ к другим частям состояния в Redux reducer

Я использую Redux и хотел бы установить флаг в состоянии, если пользователь изменил данные.

сначала я увлажняю свой магазин некоторыми данными с сервера:

let serverData = {toggle: true}
const store = configureStore({data: serverData, originalData: serverData})

у меня тогда есть несколько редукторов:

function data(state = {}, action) {
  switch (action.type) {
    case TOGGLE:
      return {
        ...state,
        toggle: !state.toggle
      }
    default:
      return state
  }
}

function changed(state = false, action) {
  // This doesn't work; we are actually comparing state.changed.originalData and state.changed.data
  return isEqual(state.originalData, state.data)
}

const rootReducer = combineReducers({
  data,
  originalData: (state={}) => state,
  changed
})

что я хотел бы сделать здесь, это установить changed флаг true, если state.data не равно state.originalData. Однако, используя combineReducers, я не могу получить доступ к этим частям состояния внутри моего changed редуктор.

что больше всего идиоматические способ сделать это?

1 ответов


Мишель права, чтобы расширить его в традиционных терминах потока, подумайте о редукторе как о магазине, вы просто назвали один из ваших магазинов "данными", а другой "измененным" - это не семантика и показывает, что вы, вероятно, смущены тем, как они используются.

код changed редуктор должен либо вернуть немодифицированное состояние, либо, если было сделано действие, которое его интересует, вернуть далее государство. Это не для выяснения, изменился ли ваш магазин - вот что subscribe для.

const unsubscribe = store.subscribe(() =>
  console.log('store was changed:', store.getState())
)

когда вы называете combineReducers он вызовет каждый редуктор один раз, с действием @@redux/INIT -- но не беспокойтесь об этом, поскольку это внутреннее. Важно понимать,что под каждым ключом редуктора инициализируется состояние. В вашем случае вы инициализировали data к пустому объекту,changed false, а originalData к пустому объекту.

следующий, когда вы позвонили createStore вы сказали "обновить магазины" data " и "originalData" с это начальное состояние от сервера". Итак, теперь состояние хранилищ "data" и "serverData" равно {toggle: true}.

в этот момент оба объекта одинаковы.

впоследствии, когда вы называете store.dispatch все ваши редукторы будут вызваны, чтобы они могли иметь возможность изменять состояние (и возвращать новый объект) под каждым ключом редуктора. Каждый редуктор имеет доступ только к своему собственному состоянию. Поэтому в вашем changed редуктор вы не можете проверить в целом объектное равенство всего вашего государства.

однако вы можете проверить равенство объектов в подписке (смешанный ES5/6 здесь для Chrome 47)

'use strict';

const serverData = {toggle: true};
const TOGGLE = 'TOGGLE';

function data(state, action) {
    state = state || {};
  switch (action.type) {
    case TOGGLE:
        return Object.assign({}, state, {
        toggle: !state.toggle
      })
    default:
      return state
  }
}

function originalData(state) {
    state = state || {};
  return state;
}

const rootReducer = Redux.combineReducers({
  data,
  originalData
});

const store = Redux.createStore(rootReducer, {data: serverData, originalData: serverData });

const unsubscribe = store.subscribe(() =>
  console.log('on change equal?', store.getState().data === store.getState().originalData)
)

console.log('on load equal?', store.getState().data === store.getState().originalData);

store.dispatch({ type: TOGGLE });

консоль.вывод журнала должен быть:

on load equal? true
on change equal? false

Скрипка:https://jsfiddle.net/ferahl/5nwfqo9k/1/