Redux: Pergunta: Mutação de um objeto interno em um estado em um redutor

Criado em 15 abr. 2016  ·  3Comentários  ·  Fonte: reduxjs/redux

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:

  • expandir um subnó (por exemplo byId ) em um estado anterior mostrará o mesmo valor que o último, mesmo quando era outra coisa anteriormente
  • viagem no tempo não está funcionando

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

Comentários muito úteis

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

Todos 3 comentários

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

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

cloudfroster picture cloudfroster  ·  3Comentários

rui-ktei picture rui-ktei  ·  3Comentários

wmertens picture wmertens  ·  4Comentários

jimbolla picture jimbolla  ·  3Comentários

vslinko picture vslinko  ·  3Comentários