2015-04-21 3 views
15

Supponiamo che io sono i seguenti record definita utilizzando Immutable.js:Parsing Records annidati in Immutable.js

var Address = Immutable.Record({street: '', city: '', zip: ''}); 
var User = Immutable.Record({name: '', address: new Address()}); 

Come posso convertire oggetto pianura javascript nel record utente? Ho provato quanto segue ma non produrre i risultati attesi:

var user = new User({name: 'Foo', address: {street: 'Bar', city: 'Baz'}}); 
// => Record { "name": "Foo", "address": [object Object] } 

Sono consapevole che è possibile creare in modo esplicito il record Indirizzo:

var user = new User({name: 'Foo', address: new Address({street: 'Bar', city: 'Baz'})}); 
// => Record { "name": "Foo", "address": Record { "street": "Bar", "city": "Baz", "zip": "" } } 

ma che non è la soluzione che sto cercando . Immagina di avere record nidificati a diversi livelli e desideri archiviare/recuperare i dati come JSON (ad esempio nel database). Vorrei utilizzare la struttura del record Utente reale come informazioni sullo schema per ricreare i record nidificati. O c'è un modo migliore per rappresentare i dati immutabili nidificati e strutturati?

+2

È possibile controllare l'argomento 'reviver' in' Immutable.fromJs', consultare http://stackoverflow.com/questions/28639878/how-to-create-a-map-of-records-from-a-javascript- raw-object-with-immutable-js – OlliM

+1

Per rendere la domanda più chiara, è necessario specificare che si desidera 'nuovo utente ({nome: 'Foo', indirizzo: {via: 'Bar', città: 'Baz'}}). indirizzo instanceof Address' per essere vero. – Andy

risposta

8

L'uso previsto di Struttura record non è verificare la struttura dei dati forniti, solo per determinare l'insieme di chiavi consentite e fornire valori predefiniti se non vengono forniti.

Così, attraverso il tuo esempio, se si inizializza il record senza fornire indirizzo, si otterrà l'oggetto Immutable.Record adeguato per Indirizzo:

var user = new User({name: 'Foo'}); 
// => Record { "name": "Foo", "address": Record { "street": "", "city": "", "zip": "" } } 

Uno hackish modo per ottenere ciò che si desidera sarebbe quello di scrivere un involucro in Immutable.fromJS metodo con funzione personalizzata reviver:

Immutable.Record.constructor.prototype.fromJS = function(values) { 
    var that = this; 
    var nested = Immutable.fromJS(values, function(key, value){ 
    if(that.prototype[key] && that.prototype[key].constructor.prototype instanceof Immutable.Record){return that.prototype[key].constructor.fromJS(value)} 
    else { return value } 
    }); 
    return this(nested); 
} 

quindi è possibile utilizzare in questo modo:

var user = User.fromJS({name: 'Foo', address: {street: 'Bar', city: 'Baz'}}); 

// => User { "name": "Foo", "address": Record { "street": "Bar", "city": "Baz", "zip": "" } } 

Tuttavia, se si vuole avere una corretta verifica la strutture di dati, mi consiglia di utilizzare Immutable.js insieme con un certo tipo-checker statico, come http://flowtype.org/ o http://www.typescriptlang.org/

+3

In realtà il mio intento non era quello di verificare la struttura dei dati ma di nascondere il fatto che i dati passati ai componenti figlio sono immutabili. Quando si passa Immutable.Map al componente figlio, deve esserne a conoscenza e utilizzare data.get ('pippo') invece di data.foo. Ho provato a risolvere questo problema utilizzando Record, che definisce le proprietà dell'oggetto, in modo che il componente figlio (che esegue solo il rendering dei dati) possa semplicemente utilizzare data.foo senza preoccuparsi se i dati sono immutabili o meno. – dkl

+0

Il vero problema è deserializzare automaticamente l''indirizzo' da semplice JSON in un record' Address' nel costruttore 'User'. – Andy

+0

Questo è intelligente. Mi è piaciuto molto. Poi ho scoperto che dal momento che 'Immutable.fromJS' è bottom-to-top (lascia prima) non può essere usato per strutture profondamente annidate :( –

6

È possibile effettuare User sottoclasse la definizione Record e analizzare address nel costruttore:

import {Record} from 'immutable' 

const Address = Record({street: '', city: '', zip: ''}); 
class User extends Record({name: '', address: new Address()}) { 
    constructor({name, address} = {}) { 
    super({name, address: new Address(address)}) 
    } 
} 

const user = new User({ 
    name: 'Andy', 
    address: { 
    street: 'wherever', 
    city: 'Austin', 
    zip: 'TX' 
    } 
}) 

console.log(user) 
console.log('user.address instanceof Address:', user.address instanceof Address) 

const user2 = new User({name: 'Bob'}) 

console.log(user2) 
console.log('user2.address instanceof Address:', user2.address instanceof Address) 

uscita:

User { "name": "Andy", "address": Record { "street": "wherever", "city": "Austin", "zip": "TX" } } 
user.address instanceof Address: true 
User { "name": "Bob", "address": Record { "street": "", "city": "", "zip": "" } } 
user2.address instanceof Address: true 
+0

Che dire di' List'? –

+0

@VictorQueiroz a seconda di dove si intende la lista ('Record' contenente un' Elenco'? 'Elenco' di' Record's?) Potrebbe implicare una combinazione di questa e della funzione 'reviver' menzionata nella risposta di cui sopra. – Andy