Este é um redutor redux válido?
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
}
}
Todo o estado é clonado superficialmente primeiro, então um novo objeto será retornado, mas os objetos internos permanecem os mesmos e sofreram mutação.
Ou tenho que fazer algo como:
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
}
}
Os efeitos colaterais que vejo com a primeira abordagem estão no DevTools LogMonitor:
byId
) em um estado anterior mostrará o mesmo valor que o último, mesmo quando era outra coisa anteriormenteÉ apenas um bug no LogMonitor ou a segunda abordagem é a correta? Se eu adicionar state = _.cloneDeep(state)
antes das mutações ele realmente funciona bem, provando que o LogMonitor reutiliza os mesmos objetos, portanto os mesmos valores.
O resto do aplicativo funciona bem e as visualizações @connect
são atualizadas corretamente.
Não, esse primeiro exemplo está mudando absolutamente o estado. A cópia superficial inicial cria um novo objeto, mas o novo objeto aponta para as mesmas referências byId
e ids
do original. Então, quando você faz byId[action.id] = action.value
e ids.push(action.id)
, você está alterando os itens originais.
O último exemplo é o que você precisa fazer. Obviamente, isso pode ficar um pouco detalhado se você estiver aninhando coisas. Existem várias bibliotecas de utilitários que tentam abstrair isso para você, e eu tenho algumas delas listadas na página de dados imutáveis da minha lista de bibliotecas Redux.
O FAQ do Redux também tem uma pergunta que abrange a atualização correta do estado de forma imutável: http://redux.js.org/docs/FAQ.html#react -not-rendering .
O último exemplo é o que você precisa fazer. Obviamente, isso pode ficar um pouco detalhado se você estiver aninhando coisas. Existem várias bibliotecas de utilitários que tentam abstrair isso para você, e eu tenho algumas delas listadas na página de dados imutáveis da minha lista de bibliotecas Redux.
Também a composição do redutor ajuda nisso.
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 Obrigado. Acabei escrevendo um redutor de alta ordem que gerencia listas indexadas dinâmicas (por ID)
Código: https://gist.github.com/elado/95484b754f31fcd6846c7e75de4aafe4
Comentários muito úteis
Também a composição do redutor ajuda nisso.