Анализ вложенных записей в Immutable.js
Предположим, что у меня есть следующие записи, определенные с помощью Immutable.js:
var Address = Immutable.Record({street: '', city: '', zip: ''});
var User = Immutable.Record({name: '', address: new Address()});
Как преобразовать простой объект javascript в запись пользователя? Я попробовал следующее, но он не дает ожидаемого результата:
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 (например, в базе данных). Я хотел бы использовать фактическую структуру записей пользователя как информацию схемы для воссоздания вложенных записей. Или есть лучший способ представления вложенных и структурированных неизменяемых данных?
Ответы
Ответ 1
Предполагаемое использование структуры записи не должно проверять структуру предоставленных данных, просто чтобы определить набор ключей, которые разрешены, и предоставить значения по умолчанию, если они не указаны.
Итак, используя ваш пример, если вы инициализируете запись без предоставления адреса, вы получите соответствующий объект 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/
Ответ 2
Вы можете сделать 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