2015-04-21 4 views
15

Пусть я следующие отчеты определяются с помощью Immutable.js:Разбор вложенных записей в Immutable.js

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

Как преобразовать обычный JavaScript Object в записи пользователя? Я попытался следующие, но это не дает ожидаемого результата:

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

Я знаю, что можно явно создать адресную запись:

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

Но это не решение, которое я ищу , Представьте, что у вас есть записи, вложенные на несколько уровней в глубину и вы хотите хранить/извлекать данные как JSON (например, в базе данных). Я хотел бы использовать фактическую структуру записей пользователя как информацию схемы для воссоздания вложенных записей. Или существует лучший способ представления вложенных и структурированных неизменяемых данных?

+2

Вы можете проверить аргумент 'reviver' в' Immutable.fromJs', см. Http://stackoverflow.com/questions/28639878/how-to-create-a-map-of-records-from-a-javascript- raw-object-with-immutable-js – OlliM

+1

Чтобы сделать вопрос понятным, вы должны указать, что хотите использовать новый пользователь ({name: 'Foo', адрес: {street: 'Bar', city: 'Baz'}}). адрес instanceof Address' должен быть правдой. – Andy

ответ

8

Предполагаемое использование структуры записи не должно проверять структуру предоставленных данных, просто чтобы определить набор ключей, которые разрешены, и предоставить значения по умолчанию, если они не указаны.

Таким образом, используя ваш пример, если вы инициализировать запись без предоставления адреса, вы получите правильный объект Immutable.Record Адрес:

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

Один хаком способ добиться того, что вы хотите, будет написать обертку на Immutable.fromJS метод с пользовательскими 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); 
} 

Затем вы можете использовать его как это:

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

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

Однако, если вы хотите иметь надлежащий контроль свои структуры данных, я бы рекомендовал использовать Immutable.js вместе с некоторым статическим типом-чекер, как http://flowtype.org/ или http://www.typescriptlang.org/

+3

На самом деле, мое намерение состояло в том, чтобы не проверять структуру данных, а скрывать тот факт, что данные, переданные дочерним компонентам, неизменны. Когда вы передаете дочерний компонент Immutable.Map, он должен знать об этом и использовать data.get ('foo') вместо data.foo. Я попытался обойти это с помощью записи, которая определяет свойства объекта, так что дочерний компонент (который просто отображает данные) может просто использовать data.foo, не заботясь о том, являются ли данные неизменными или нет. – dkl

+0

Настоящая проблема заключается в том, чтобы автоматически десериализовать «адрес» из простого JSON в запись «Адрес» в конструкторе «Пользователь». – Andy

+0

Это умный. Мне это очень понравилось. Затем я обнаружил, что, поскольку «Immutable.fromJS» находится внизу-сверху (сначала уходит), он не может использоваться для глубоко вложенных структур :( –

6

Вы можете сделать User подкласс Record определения и синтаксический address в конструкторе:

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) 

Выход:

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

Что относительно 'List'? –

+0

@ VictorQueiroz в зависимости от того, где вы имеете в виду список ('Record', содержащий« Список »?' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' – Andy

Смежные вопросы