2015-10-24 12 views
7

Sto cercando di elaborare il modo ideale per aggiornare diversi campi di primo livello nella struttura dello stato, pur mantenendo i riduttori di divisione.Il modo migliore per aggiornare i relativi campi di stato con riduttori split?

Ecco una soluzione semplice che ho trovato.

var state = { 
    fileOrder: [0], 
    files: { 
    0:{ 
     id: 0, 
     name: 'asdf' 
    } 
    } 
}; 

function handleAddFile(state, action) { 
    return {...state, ...{[action.id]:{id: action.id, name: action.name}}}; 
}; 

function addFileOrder(state, action) { 
    return [...state, action.id]; 
} 

// Adding a file should create a new file, and add its id to the fileOrder array. 
function addFile(state, action) { 
    let id = Math.max.apply(this, Object.keys(state.files)) + 1; 
    return { 
    ...state, 
    fileOrder: addFileOrder(state.fileOrder, {id}), 
    files: handleAddFile(state.files, {id, name: action.name}) 
    }; 
} 

Attualmente sono in grado di inviare una singola azione {type: ADD_FILE, fileName: 'x'}, quindi addFile crea un'azione internamente per inviare addFileOrder e addFile.

Sono curioso di sapere se è considerato un approccio migliore per eseguire una delle seguenti operazioni.

Invece di inviare due azioni, una per aggiungere un file, quindi ottenere il suo id e inviare un'azione ADD_TO_FILE_ORDER con l'id. OPPURE Fuoco e azioni come {type: ADD_FILE, name: 'x', id: 1}, invece di consentire addFile per calcolare il nuovo ID. Questo mi permetterebbe di usare combineReducers e filtrare sul tipo di azione. Questo esempio è probabilmente banale, ma il mio albero di stato attuale è un po 'più complicato, con ogni file aggiunto che deve essere aggiunto ad altre entità.

Per un ulteriore contesto, un albero di stato più completo sarebbe simile a questo.

{ 
    "fileOrder": [0] 
    "entities": { 
     "files": { 
      0: { 
       id: 0, 
       name: 'hand.png' 
      } 
     }, 
     "animations": { 
      0: { 
       id: 0, 
       name: "Base", 
       frames: [0] 
      } 
     }, 
     "frames": { 
      0: { 
       id: 0, 
       duration: 500, 
       fileFrames: [0] 
      } 
     }, 
     "fileFrames": { 
      0: { 
       id: 0, 
       file: 0, 
       top: 0, 
       left: 0, 
       visible: true 
      }   
     } 
    } 
} 

Aggiunta di un file avrebbe bisogno di:

  1. aggiungerlo al file hash.
  2. Aggiungilo all'array fileOrder.
  3. Aggiungere un fileFrame che fa riferimento al file, per ciascun fotogramma.
  4. Aggiungi ogni nuovo fileFrame al frame per il quale è stato creato.

Gli ultimi due punti mi chiedo se sarei in grado di utilizzare CombinaRiduttori affatto.

risposta

7

Alla fine ho trovato una soluzione piuttosto semplice a questo problema.

Entrambi questi blocchi della documentazione sono funzionalmente la stessa cosa.

const reducer = combineReducers({ 
    a: doSomethingWithA, 
    b: processB, 
    c: c 
}); 

// This is functionally equivalent. 
function reducer(state, action) { 
    return { 
    a: doSomethingWithA(state.a, action), 
    b: processB(state.b, action), 
    c: c(state.c, action) 
    }; 
} 

Ho finito con il tweaking del secondo blocco e passando sempre il mio albero di stato globale. Fintanto che nulla modifica lo stato lungo la strada, tutti i riduttori funzionano bene.

// Simple change to pass the entire state to each reducer. 
// You have to be extra careful to keep state immutable here. 
function reducer(state, action) { 
    return { 
    a: doSomethingWithA(state.a, action, state), 
    b: processB(state.b, action, state), 
    c: c(state.c, action, state) 
    }; 
} 
2

Sulla soluzione dell'autore:

Ho avuto questo stesso problema, in cui ho bisogno (solo un po ') l'accesso al di fuori di una parte del mio riduttore della dello Stato. Penso che questa soluzione possa funzionare in pratica se sei diligente nel non cambiare nulla oltre a un singolo valore come una bandiera o un contatore.

È impurità potrebbe diventare pazzo veloce se altri sviluppatori non erano così riservati con il loro codice. Immagina cosa succederebbe se iniziasse a cambiare la parte di b e c dello stato, b cambiando la parte di e c e così via.

Si potrebbe considerare riducendo la superficie di impurità come questo:

function reducer(state, action) { 
    return { 
    a: doSomethingWithA(state.a, action, state.globals), 
    b: processB(state.b, action, state.globals), 
    c: c(state.c, action, state.globals) 
    }; 
}