¿Es este un reductor 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 el estado se clona superficialmente primero, por lo que se devolverá un nuevo objeto, pero los objetos internos permanecen iguales y mutados.
O tengo que hacer 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
}
}
Los efectos secundarios que veo con el primer enfoque están en DevTools LogMonitor:
byId
) en un estado anterior mostrará el mismo valor que el último, incluso cuando anteriormente era otra cosa¿Es solo un error en LogMonitor o el segundo enfoque es el correcto? Si agrego state = _.cloneDeep(state)
antes de las mutaciones, en realidad funciona bien, lo que demuestra que LogMonitor reutiliza los mismos objetos, por lo tanto, los mismos valores.
Sin embargo, el resto de la aplicación funciona bien y las vistas @connect
ed se actualizan correctamente.
No, ese primer ejemplo está mutando absolutamente el estado. La copia superficial inicial crea un nuevo objeto, pero el nuevo objeto apunta a las mismas referencias byId
y ids
que el original. Entonces, cuando haces byId[action.id] = action.value
y ids.push(action.id)
, estás mutando los elementos originales.
El último ejemplo es lo que debe hacer. Obviamente, eso puede volverse algo detallado si estás anidando cosas. Hay varias bibliotecas de utilidades que intentan abstraer eso para usted, y tengo algunas de ellas enumeradas en la página de Datos inmutables de mi lista de bibliotecas Redux.
Las preguntas frecuentes de Redux también tienen una pregunta que cubre la actualización correcta del estado de forma inmutable: http://redux.js.org/docs/FAQ.html#react -not-rerendering .
El último ejemplo es lo que debe hacer. Obviamente, eso puede volverse algo detallado si estás anidando cosas. Hay varias bibliotecas de utilidades que intentan abstraer eso para usted, y tengo algunas de ellas enumeradas en la página de Datos inmutables de mi lista de bibliotecas Redux.
También la composición reductora ayuda con esto.
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 Gracias. Terminé escribiendo un reductor de alto orden que administra listas indexadas dinámicas (por ID)
Código: https://gist.github.com/elado/95484b754f31fcd6846c7e75de4aafe4
Comentario más útil
También la composición reductora ayuda con esto.