2015-08-21 19 views
46

Qual è il modo migliore/corretto per aggiornare una matrice nidificata di dati in un negozio utilizzando redux?Aggiornamento dei dati nidificati nell'archivio di ridondanza

Il mio negozio si presenta in questo modo:

{ 
    items:{ 
     1: { 
      id: 1, 
      key: "value", 
      links: [ 
       { 
        id: 10001 
        data: "some more stuff" 
       }, 
       ... 
      ] 
     }, 
     ... 
    } 
} 

ho un paio di azioni asincrone che aggiorna il completo items oggetto, ma ho un altro paio di azioni che voglio aggiornare una specifica links array.

mio riduttore attualmente appare come questo, ma non sono sicuro se questo è l'approccio corretto:

switch (action.type) { 
    case RESOURCE_TYPE_LINK_ADD_SUCCESS: 
     // TODO: check whether the following is acceptable or should we create a new one? 
     state.items[action.resourceTypeId].isSourceOf.push(action.resourceTypeLink); 
     return Object.assign({}, state, { 
     items: state.items, 
     }); 
    } 

risposta

49

Reagire di update() immutability helper è un modo conveniente per creare una versione aggiornata di un oggetto semplice JavaScript vecchio, senza mutare lo .

Gli si assegna l'oggetto sorgente da aggiornare e un oggetto che descrive i percorsi dei pezzi che devono essere aggiornati e le modifiche da apportare.

esempio, se un'azione avesse id e link proprietà e voluto spingere il link a una matrice di collegamenti in un elemento calettato con il id:

var update = require('react/lib/update') 

// ... 

return update(state, { 
    items: { 
    [action.id]: { 
     links: {$push: action.link} 
    } 
    } 
}) 

(Esempio utilizza un nome di proprietà calcolato ES6 per action.id)

+5

Si noti che update() è stato dichiarato obsoleto a favore di https://github.com/kolodny/immutability-helper –

+0

Sono curioso di sapere perché non si è scelto di utilizzare 'Object.assign()'? – HussienK

+0

@HussienK Non 'Object.assign' esegue una copia superficiale? –

57

Jonny's answer è corretto (non muta mai lo stato assegnato a te!) Ma volevo aggiungere un altro punto ad esso. Se tutti i tuoi oggetti hanno ID, è generalmente una cattiva idea mantenere la forma di stato annidata.

Questo:

{ 
    items: { 
    1: { 
     id: 1, 
     links: [{ 
     id: 10001 
     }] 
    } 
    } 
} 

è una forma che è difficile da aggiornare.

Non deve essere così! È invece possibile memorizzare in questo modo:

{ 
    items: { 
    1: { 
     id: 1, 
     links: [10001] 
    } 
    }, 
    links: { 
    10001: { 
     id: 10001 
    } 
    } 
} 

Questo è molto più facile per l'aggiornamento perché non v'è una sola copia canonica di qualsiasi entità. Se è necessario consentire all'utente di "modificare un collegamento", c'è solo un posto dove deve essere aggiornato, ed è completamente indipendente dallo items o da qualsiasi altro riferimento a links.

Per ottenere le risposte API in tale forma, è possibile utilizzare normalizr. Una volta che i soggetti all'interno delle azioni del server sono normalizzati, è possibile scrivere un semplice riduttore che li fonde in stato attuale:

import merge from 'lodash/object/merge'; 

function entities(state = { items: {}, links: {} }, action) { 
    if (action.response && action.response.entities) { 
    return merge({}, state, action.response.entities); 
    } 

    return state; 
} 

Si prega di vedere Redux real-world esempio per una demo di tale approccio.

+0

Sto usando normalizr ma ho anche bisogno degli articoli nello stesso ordine in cui sono entrati nella risposta dell'API. Stavo pensando di implementare una "lista collegata" usando gli id ​​delle entità, ma mi chiedo se invece ci sia un approccio migliore. –

+0

@hisa_py Dovrai conservare separatamente un array di ID. Gli esempi di 'real-world' e' shopping-cart' nel repository Redux lo fanno. –

+1

Thx @Dan ... Bello e semplice ... Ora ricordo che l'ho visto prima negli esempi –

Problemi correlati