2017-05-25 4 views
0

Je suis nouveau pour réagir et redux. J'ai un objet est un tableau d'objets d'enfant, qui contiennent des tableauxRemplacer l'objet enfant profond, tout en gardant l'état immuable dans React

const initialState = { 
    sum: 0, 
    denomGroups: [ 
     { 
      coins: [ 
       { name: 'Penny', namePlural: 'Pennies', label: '1¢', value: .01, sum: 0 }, 
       { name: 'Nickel', namePlural: 'Nickels', label: '5¢', value: .05, sum: 0 }, 
       { name: 'Dime', namePlural: 'Dimes', label: '10¢', value: .10, sum: 0 }, 
       { name: 'Quarter', namePlural: 'Quarters', label: '25¢', value: .25, sum: 0 } 
      ] 
     }, 
     { 
      bills: [ 
       { name: 'Dollar', namePlural: 'Dollars', label: '$1', value: 1, sum: 0 }, 
       { name: 'Five', namePlural: 'Fives', label: '$5', value: 5, sum: 0 }, 
       { name: 'Ten', namePlural: 'Tens', label: '$10', value: 10, sum: 0 }, 
       { name: 'Twenty', namePlural: 'Twentys', label: '$20', value: 20, sum: 0 }, 
       { name: 'Fifty', namePlural: 'Fiftys', label: '$50', value: 50, sum: 0 }, 
       { name: 'Hundred', namePlural: 'Hundreds', label: '$100', value: 100, sum: 0 } 
      ] 
     } 
    ] 
}; 

J'ai une action qui est passé une valeur et le nom de la dénomination

export function increaseSum(value, denom) { 
    return { type: types.ADD_TO_SUM, value: value, denom: denom } 
} 

A l'intérieur de mon réducteur j'ai écrit un classe aide pour identifier où cette dénomination est dans l'objet:

function findDenomination(denoms, action) { 
    let denomMap = {}, 
     currentDenom = {}; 
    for (let i = 0; denoms.length >= i + 1; i++) { 
     let denomGroup = denoms[Object.keys(denoms)[i]]; 
     for (var key in denomGroup) { 
      if (!currentDenom.length) { 
       currentDenom = denomGroup[key].filter(x => x.name === action.denom); 
       if (currentDenom.length > 0) { 
        denomMap.group = i; 
        denomMap.key = key; 
        denomMap.index = denomGroup[key].findIndex(x => x.name === action.denom); 
       } 
      } 
     } 
     if (currentDenom.length > 0) { 
      break; 
     } 
    } 
    return denomMap; 
} 

Et dans le réducteur lui-même, je me sers Object.assign pour faire une copie profonde de la denomGroup s, d'une manière que je pense pense le maintient immuable.

function countableItems(state = initialState, action) { 
    switch (action.type) { 
     case types.ADD_TO_SUM: 
      let denomMap = findDenomination(state.denomGroups, action); 
      state.denomGroups = Object.assign({}, state.denomGroups, state.denomGroups[denomMap.group][denomMap.key][denomMap.index].sum = parseFloat(action.value)); 
      return state; 
     default: 
      return state; 
    } 
} 

Est-il clair à tout le monde pourquoi cela se marqué avec l'erreur: A state mutation was detected inside a dispatch

+1

Vous êtes en train de modifier l'état: '' state.denomGroups = ... – Li357

+1

'retour Object.assign ({}, état, state.denomGroups [denomMap.group] [ denomMap.key] [denomMap.index] .sum = parseFloat (action.value)); 'lance toujours une erreur de mutation –

+0

' state.denomGroups [denomMap.group] [denomMap.key] [denomMap.ind ex] .sum = parseFloat (action.value) 'est toujours une mutation d'état – Li357

Répondre

1

Vous avez tenté de muter un immuable. D'où l'erreur.

Le point entier des immutables est qu'un immuable ne devrait jamais changer n'importe où à l'intérieur après qu'il soit créé. C'est pourquoi toutes les fonctions qui le modifient créent une nouvelle instance d'un immutable. Si vous essayez de changer quelque chose de profond à l'intérieur d'un immuable, c'est toujours une mutation, et donc une mauvaise chose. Cela garantit que vous pouvez vérifier les objets eux-mêmes pour l'égalité au lieu d'avoir à faire une vérification approfondie, ainsi que d'assurer l'intégrité des données. Ce que vous devez faire est de le muter (si vous utilisez la bibliothèque immutables, vous pouvez utiliser setIn), ce qui créera une nouvelle carte. Vous pouvez appeler cela simplement sur state.

Quelque chose comme ceci:

case types.ADD_TO_SUM: 
    const denomMap = findDenomination(state.denomGroups, action); 
    return state.setIn(['denomGroup', denomGroup.key, denomGroup.index, sum], parseFloat(action.value)); 
+0

Avez-vous tendance à toujours utiliser la bibliothèque' immutables'? –

+1

Alors qu'une réponse complète est plus de place que j'ai ici, en bref, j'essaie de certaines choses, comme l'état Redux. Le gros avantage est que si vous avez un immutable pour les données, quand vous le passez à un 'React.PureComponent', il peut déterminer de manière fiable (sans avoir besoin d'une vérification approfondie) si l'objet a changé et s'il doit être rendu ou non . – samanime