Redux: Pregunta: Mutación de un objeto interno en un estado en un reductor

Creado en 15 abr. 2016  ·  3Comentarios  ·  Fuente: reduxjs/redux

¿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:

  • expandir un subnodo (por ejemplo byId ) en un estado anterior mostrará el mismo valor que el último, incluso cuando anteriormente era otra cosa
  • viajar en el tiempo no funciona

¿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.

Comentario más útil

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
})

Todos 3 comentarios

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

¿Fue útil esta página
0 / 5 - 0 calificaciones