2015-04-21 57 views
15

Giả sử tôi đã Records sau được xác định bằng Immutable.js:Phân tích ghi lồng nhau trong Immutable.js

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

Làm thế nào để chuyển đổi đối tượng đồng bằng javascript vào kỷ lục tài khoản? Tôi đã thử các sau đây nhưng nó không cho kết quả mong đợi:

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

Tôi biết rằng nó có thể tạo ra một cách rõ ràng kỷ lục Địa chỉ:

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

Nhưng đó không phải là giải pháp tôi đang tìm kiếm . Hãy tưởng tượng bạn có Records lồng nhau nhiều cấp độ sâu và muốn lưu trữ/lấy dữ liệu dưới dạng JSON (ví dụ: trong cơ sở dữ liệu). Tôi muốn sử dụng cấu trúc bản ghi Người dùng thực tế làm thông tin lược đồ để tạo lại các bản ghi lồng nhau. Hoặc có cách nào tốt hơn để thể hiện dữ liệu không thay đổi được cấu trúc lồng nhau không?

+2

Bạn có thể kiểm tra đối số 'reviver' trong' Immutable.fromJs', xem http://stackoverflow.com/questions/28639878/how-to-create-a-map-of-records-from-a-javascript- raw-object-with-immutable-js – OlliM

+1

Để làm cho câu hỏi rõ ràng hơn, bạn nên nói rằng bạn muốn 'người dùng mới ({name: 'Foo', địa chỉ: {street: 'Bar', thành phố: 'Baz'}}). địa chỉ instanceof Address' là true. – Andy

Trả lời

8

Mục đích sử dụng Cấu trúc bản ghi không phải là để xác minh cấu trúc của dữ liệu được cung cấp, chỉ để xác định bộ khóa được phép và cung cấp giá trị mặc định nếu chúng không được cung cấp.

Vì vậy, sử dụng ví dụ của bạn, nếu bạn khởi tạo các bản ghi mà không cung cấp địa chỉ, bạn sẽ nhận được các đối tượng Immutable.Record thích hợp cho Địa chỉ:

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

Một hackish cách để đạt được những gì bạn muốn sẽ được viết một wrapper trên Immutable.fromJS phương pháp với tùy chỉnh reviver chức năng:

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

Sau đó, bạn có thể sử dụng nó như thế này:

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

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

Tuy nhiên nếu bạn muốn có thích hợp kiểm tra cấu trúc dữ liệu của bạn, tôi sẽ khuyên bạn nên sử dụng Immutable.js cùng với một số loại tĩnh trình kiểm tra, như http://flowtype.org/ hoặc http://www.typescriptlang.org/

+3

Thực ra ý định của tôi là không xác minh cấu trúc của dữ liệu nhưng để che giấu thực tế là dữ liệu được truyền cho các thành phần con là không thay đổi. Khi bạn vượt qua Immutable.Map thành phần con, nó phải được nhận thức của nó và sử dụng data.get ('foo') thay vì data.foo. Tôi đã cố gắng giải quyết vấn đề này bằng cách sử dụng Record, để xác định các thuộc tính của đối tượng, để thành phần con (chỉ hiển thị dữ liệu) có thể sử dụng data.foo mà không cần quan tâm liệu dữ liệu có thay đổi hay không. – dkl

+0

Vấn đề thực sự là tự động deserialize 'địa chỉ' từ JSON đơn giản thành một bản ghi' Address' trong constructor 'User'. – Andy

+0

Điều này là thông minh. Tôi rất thích nó. Sau đó, tôi phát hiện ra rằng kể từ 'Immutable.fromJS' là từ dưới lên trên (lá đầu tiên) nó không thể được sử dụng cho các cấu trúc lồng nhau sâu sắc: ( –

6

Bạn có thể làm User lớp con định nghĩa Record và phân tích address trong constructor:

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) 

Output:

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

Điều gì về' List'? –

+0

@VictorQueiroz tùy thuộc vào nơi bạn có nghĩa là danh sách ('Record' có chứa một' List'? 'List' của' Record's?) Nó có thể liên quan đến một sự kết hợp của điều này và 'reviver' chức năng được đề cập trong câu trả lời ở trên. – Andy

Các vấn đề liên quan