2015-11-16 12 views
10

Io uso il redux con normalizr per normalizzare la risposta dal server, in pratica segui l'esempio real-world. In questo modo il riduttore entities è molto semplice, basta unire la risposta. Il problema che ho adesso è una specie di operazione delete. Ho trovato questo issue#21 of normalizr repo ma ancora non riuscivo a capire come risolvere questo. Ad esempio,Operazione Redux + Normalizr staccata (cancellata)

Stato attuale è

{ 
    entities: 
    product_categories: { 
     ... 
     13: { 
     ... 
     products: ["1", "2"], <--------------- [i] Current state 
     ... 
     } 
    }, 
    products: { 
     1: { 
     id: "1" 
     } 
    } 
} 

La risposta normalizzato è

{ 
    ... 
    product_categories: { 
     ... 
     13: { 
     ... 
     products: ["1"], <---------------- [2] Normalized result 
     } 
    ... 
} 

Come si può vedere, l'API di back-end appena restituisce tutti gli ID di prodotto che appartenevano a questa categoria, in questo caso "2" è staccato. Quando il riduttore 'entità' unisce questa risposta, "2" è ancora in agguato. Proprio ora ricarico la pagina, ma mi chiedo se c'è un modo migliore per gestire questo caso?

Nel riduttore entities, è sufficiente unirlo come nell'esempio reale.

return merge({}, state, action.payload.entities);

+1

Questa è una bella domanda. IMO indica un difetto sostanziale nell'intera architettura Redux + Normalizr. Certo, hai un'unica radice da dichiarare, ma non è esattamente una rappresentazione veritiera. Richiedere l'uso di delete flag è troppo supponente –

risposta

12

Proprio non ti preoccupare che sia lì. Pensa al tuo stato come a un database. Non si eliminano veramente record dal database per evitare complicate cascate, in genere si cambia semplicemente il loro stato nel database. Allo stesso modo, con Normalizer, invece di eliminare veramente le entità, lasciarle in cache fino a quando l'utente non lascia la pagina!

+0

Cosa intendi con "non cancelli veramente i record dal database"? –

+0

Invece di rimuovere un elemento da una matrice, si aggiunge una bandiera denominata "cancellata" o qualcosa del genere. Quindi aggiorna il selettore su 'items.filter (item =>! Item.deleted)' –

0

Di seguito è una spiegazione della mia soluzione seguita dal codice.

Per eseguire un'eliminazione, ho aggiornato il mio riduttore a un comando di eliminazione: REMOVE_ENTITY_ITEM. Nell'azione si passa a id e name dell'entità da rimuovere.

Nel riduttore ho prima eliminato l'entità stessa che è a store.entities[entityName][entityId]. Quindi ho bisogno di rimuovere il suo id da tutte le altre entità che potrebbero farvi riferimento. Dal momento che sto usando normalizr tutte le mie entità sono piatte e se si riferiscono a un'altra entità, avranno solo il suo id in una matrice. Ciò rende relativamente semplice rimuovere il riferimento. Faccio un giro su tutte le entità e filtra il riferimento all'entità da rimuovere.

Io uso questo approccio in combinazione con gli altri due approcci di # 1.) Aggiornamento dell'app/stato e # 2.) Capovolgimento del bit di stato delle entità piuttosto che eliminare e quindi filtrare gli elementi disattivati ​​nell'interfaccia utente. Questi approcci sono stati ben discusso here

const entities = (state={}, action) => { 
    if(action.payload && action.payload.entities) { 
    return merge({} , state, action.payload.entities); 
    }else{ 
    return deleteHandlingReducer(state, action) 
    } 
} 

const deleteHandlingReducer = (state=initialSate, action) => { 
    switch(action.type){ 
    case "REMOVE_ENTITY_ITEM": 
     if (!action.meta || !action.meta.name || !action.meta.id) { 
     return state; 
     }else{ 
     let newState = Object.assign({}, state); 
     if(newState[action.meta.name]){ 
      delete newState[action.meta.name][action.meta.id]; 
      Object.keys(state).map(key => { 
      let entityHash = state[key]; 
      Object.keys(entityHash).map(entityId => { 
       let entity = entityHash[entityId]; 
       if(entity[action.meta.name] && 
       Array.isArray(entity[action.meta.name])){ 
        entity[action.meta.name] = entity[action.meta.name]. 
        filter(item => item != action.meta.id) 
       } 
      }); 
      }) 
     } 
     return newState; 
     } 
    default: 
     return state; 
    } 
} 

Ora per eliminare i licenzio un'azione come questa:

store.dispatch({ 
    type: "REMOVE_ENTITY_ITEM", 
    meta: { 
    id: 1, 
    name: "job_titles" 
    } 
});