Immutable.fromJS() is not deep

半腔热情 提交于 2019-12-10 21:38:14

问题


The description of Immutable.fromJS is:

Deeply converts plain JS objects and arrays to Immutable Maps and Lists.

But that's wrong. I have an object with the following structure. The capitalized items are ES6 classes.

Foo
  prop1
  prop2
  bars
    Bar
      prop1
      prop2
    Bar
      prop1
      prop2
  bazes
    Baz
      prop1
      prop2
      bars
        Bar
          prop1
          prop2
        Bar
          prop1
          prop2
    Baz
      prop1
      prop2
      bars
        Bar
          prop1
          prop2
        Bar
          prop1
          prop2

The result of Immutable.fromJS(foo) is a Map. The arrays bars and bazes are Lists. However, each element of these lists is still a plain (ES6) object. The bars property of each Baz is an array, not a list.

Am I doing something wrong, or is the documentation incorrect?

Maybe the deep feature is not supported for ES6 objects? If that's the case, how can I make my object deeply immutable?

UPDATE:

This works but feels kinda gross: Immutable.fromJS(JSON.parse(JSON.stringify(foo)))


回答1:


The very first sentence in the docs for fromJS is:

Deeply converts plain JS objects and arrays to Immutable Maps and Lists.

If Foo, Bar, and Baz are ES6 classes then they are neither plain JS objects nor arrays—they're instances of a class. So, no, the docs are not incorrect.

As an aside, if Immutable.fromJS automatically converted any object it encountered into a plain JS object, as you seem to have expected it to, that would be very surprising behavior to most users, and not at all desirable.

But since that's the behavior you want, you'll be happy to know that the Immutable wiki has a section on this exact topic, which I'll duplicate here for posterity:

Here is an example which will convert any Object, including exotic Objects, to Immutable.Map:

function fromJSGreedy(js) {
  return typeof js !== 'object' || js === null ? js :
    Array.isArray(js) ? 
      Immutable.Seq(js).map(fromJSGreedy).toList() :
      Immutable.Seq(js).map(fromJSGreedy).toMap();
}

That's pretty simple. And, indeed, it works exactly as promised, as you can see by running the below snippet.

class Foo {
  constructor(name, ...children) {
    this.name = name;
    this.children = children;
  }
}

class Bar extends Foo {}
class Baz extends Foo {}

const myBar = new Bar("myBar", new Baz("myBaz1"), new Baz("myBaz2"));
const myFoo = new Foo("myFoo", myBar);

function fromJSGreedy(js) {
  return typeof js !== 'object' || js === null ? js :
    Array.isArray(js) ? 
      Immutable.Seq(js).map(fromJSGreedy).toList() :
      Immutable.Seq(js).map(fromJSGreedy).toMap();
}

console.log(fromJSGreedy(myFoo).toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>



回答2:


Additionally, I had to check for Date types because this function was converting my dates into non-date objects. This function uses typescript and lodash, but I'm sure you can alter it accordingly

export function myFromJS(js: any): any {
  return typeof js !== 'object' || js === null || (_.isDate(js)) ? js :
    Array.isArray(js) ?
      Immutable.Seq(js).map(myFromJS).toList() :
      Immutable.Seq(js).map(myFromJS).toMap();
}


来源:https://stackoverflow.com/questions/40661729/immutable-fromjs-is-not-deep

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!