2015-04-21 13 views
15

Załóżmy, że mam następujące rekordy zdefiniowana Immutable.js:parsowania zagnieżdżone Records w Immutable.js

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

Jak przekonwertować obiekt zwykły javascript w rekordzie użytkownika? Próbowałem następujących ale nie wywołuje oczekiwany wynik:

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

Mam świadomość, że możliwe jest jawnie utworzyć rekord Adres:

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

ale to nie jest rozwiązanie szukam . Wyobraź sobie, że masz Rekordy zagnieżdżone na kilku poziomach i chcesz przechowywać/pobierać dane jako JSON (np. W bazie danych). Chciałbym użyć faktycznej struktury rekordów użytkownika jako informacji o schemacie do odtworzenia zagnieżdżonych rekordów. Czy istnieje lepszy sposób na reprezentowanie zagnieżdżonych i uporządkowanych niezmiennych danych?

+2

Możesz sprawdzić argument 'reviver' w' Immutable.fromJs', zobacz http://stackoverflow.com/questions/28639878/how-to-create-a-map-of-records-from-a-javascript- raw-object-with-immutable-js – OlliM

+1

Aby wyjaśnić pytanie, powinieneś powiedzieć, że chcesz "nowy użytkownik ({imię:" Foo ", adres: {ulica:" Bar ", miasto:" Baz "}}). adres addressof Adres' jest prawdziwy. – Andy

Odpowiedz

8

Przeznaczeniem struktury rekordu nie jest weryfikacja struktury dostarczanych danych, tylko określenie zestawu kluczy, które są dozwolone i podanie wartości domyślnych, jeśli nie są podane.

Więc za pomocą przykładu, jeśli zainicjować rekord bez podania adresu, dostaniesz właściwego dla przedmiotu Immutable.Record Adres:

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

Jeden hackish sposób, aby osiągnąć to, co chcesz byłoby napisać otoki na Immutable.fromJS metody z niestandardowym reviver funkcji:

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); 
} 

Wtedy można go używać tak:

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

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

Jednak jeśli chcesz mieć właściwe sprawdzanie struktur danych, polecam korzystania Immutable.js razem z pewnym statycznym typu sprawdzania, jak http://flowtype.org/ lub http://www.typescriptlang.org/

+3

W rzeczywistości moim zamiarem nie było zweryfikowanie struktury danych, ale ukrycie faktu, że dane przekazywane do komponentów podrzędnych są niezmienne. Po przejściu Immutable.Map do komponentu potomnego, musi on być tego świadomy i użyć data.get ("foo") zamiast data.foo. Próbowałem obejść to za pomocą rekordu, który definiuje właściwości obiektu, tak aby komponent potomny (który właśnie renderuje dane) może po prostu użyć data.foo bez dbania o to, czy dane są niezmienne czy nie. – dkl

+0

Prawdziwym problemem jest automatyczne deserializowanie 'adresu' od zwykłego JSON do rekordu' Address' w konstruktorze 'User'. – Andy

+0

To jest inteligentne. Bardzo to lubiłem. Potem odkryłem, że ponieważ 'Immutable.fromJS' jest od dołu do góry (wychodzi pierwszy), nie może być używane dla struktur głęboko zagnieżdżonych :( –

6

Można dokonać User podklasy i rozdzielczości Record analizować address w konstruktorze:

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) 

wyjściowa:

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

Co z' List'? –

+0

@VictorQueiroz w zależności od tego, gdzie masz na myśli listę ('Record' zawierającą' List'? 'List'' Record's?) Może to być kombinacja tej i funkcji "reviver" wspomnianej w powyższej odpowiedzi. – Andy