Является ли это действительным редукторным редуктором?
function reducer(state={ byId: {}, ids: [] }, action) {
switch (action.type) {
case 'ADD':
state = { ...state }
state.byId[action.id] = action.value
state.ids.push(action.id)
return state
default:
return state
}
}
Сначала поверхностно клонируется все состояние, поэтому будет возвращен новый объект, но внутренние объекты останутся прежними и мутированными.
Или мне нужно сделать что-то вроде:
function reducer(state={ byId: {}, ids: [] }, action) {
switch (action.type) {
case 'ADD':
return {
...state,
byId: {
...state.byId,
[action.id]: action.value
},
ids: [ ...state.ids, action.id ]
}
default:
return state
}
}
Побочные эффекты, которые я вижу при первом подходе, находятся в DevTools LogMonitor:
byId
) в предыдущем состоянии покажет то же значение, что и последнее, даже если ранее это было что-то другоеЭто просто ошибка в LogMonitor или правильный второй подход? Если я добавлю state = _.cloneDeep(state)
перед мутациями, все будет работать нормально, доказывая, что LogMonitor повторно использует одни и те же объекты и, следовательно, одни и те же значения.
Остальная часть приложения работает нормально, и @connect
измененные представления обновляются корректно.
Нет, этот первый пример полностью мутирует состояние. Первоначальная поверхностная копия создает новый объект, но новый объект указывает на те же ссылки byId
и ids
, что и оригинал. Итак, когда вы делаете byId[action.id] = action.value
и ids.push(action.id)
, вы мутируете исходные элементы.
Последний пример — это то, что вам нужно сделать. Очевидно, что это может стать несколько многословным, если вы вкладываете вещи. Есть несколько служебных библиотек, которые пытаются абстрагировать это для вас, и некоторые из них перечислены на странице Immutable Data моего списка библиотек Redux.
В часто задаваемых вопросах Redux также есть вопрос, который охватывает правильное постоянное обновление состояния: http://redux.js.org/docs/FAQ.html#react -not-rerendering.
Последний пример — это то, что вам нужно сделать. Очевидно, что это может стать несколько многословным, если вы вкладываете вещи. Есть несколько служебных библиотек, которые пытаются абстрагировать это для вас, и некоторые из них перечислены на странице Immutable Data моего списка библиотек Redux.
Также в этом помогает редукторный состав.
function byId(state = {}, action) {
switch (action.type) {
case 'ADD':
return {
...state,
[action.id]: action.value
}
default:
return state
}
}
function ids(state = [], action) {
switch (action.type) {
case 'ADD':
return [ ...state, action.id ]
default:
return state
}
}
const reducer = combineReducers({
byId,
ids
})
@gaearon @markerikson Спасибо. В итоге я написал редуктор высокого порядка, который управляет динамическими индексированными списками (по идентификатору).
Код: https://gist.github.com/elado/95484b754f31fcd6846c7e75de4aafe4
Самый полезный комментарий
Также в этом помогает редукторный состав.