在Immutable.js中解析嵌套记录

dkl*_*dkl 15 javascript immutability immutable.js

假设我使用Immutable.js定义了以下记录:

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

如何将普通的javascript对象转换为用户记录?我尝试了以下但它不会产生预期的输出:

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

我知道可以显式创建地址记录:

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

但这不是我想要的解决方案.想象一下,你有记录嵌套了几个级别,并希望将数据存储/检索为JSON(例如在数据库中).我想使用实际的用户记录结构作为重新创建嵌套记录的模式信息.或者有更好的方法来表示嵌套和结构化的不可变数据吗?

小智 10

Record结构的预期用途不是验证提供的数据的结构,只是为了确定允许的密钥集,如果没有给出,则提供默认值.

因此,使用您的示例,如果您在不提供地址的情况下初始化记录,您将获得适用于Address的Immutable.Record对象:

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

实现你想要的一种hackishImmutable.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);
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

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

// => User { "name": "Foo", "address": Record { "street": "Bar", "city": "Baz", "zip": "" } }
Run Code Online (Sandbox Code Playgroud)

但是,如果您想要正确检查数据结构,我建议将Immutable.js与一些静态类型检查器一起使用,例如http://flowtype.org/http://www.typescriptlang.org/

  • 实际上我的意图不是验证数据的结构,而是隐藏传递给子组件的数据是不可变的这一事实.当您将Immutable.Map传递给子组件时,它必须知道它并使用data.get('foo')而不是data.foo.我尝试使用Record来解决这个问题,它定义了对象属性,因此子组件(只是呈现数据)可以简单地使用data.foo,而无需关心数据是否是不可变的. (3认同)

And*_*ndy 9

您可以在构造函数中创建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)
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)