Can I use destructuring assignment with immutable.js? - immutable.js

With standard JS objects, one can use destructuring assignment such as:
let obj = {name: 'james', code: '007'}
let {name, code} = obj // creates new variables 'name' and 'code' (with the proper values)
As suggested by some Flux / Redux evangelist, I use immutable.js for my app; can I use destructuring also on immutable List / Map? Of course, one could do:
let obj = immutable.fromJS({name: 'james', code: '007'})
let {name, code} = obj.toJS()
but this seems to have quite inefficient as the objects grow bigger (because the object needs to be deeply jsified first).

With immutable List, the destructuring works quite straightforwardly. This is because destructuring of Arrays works on every iterable (Checking whether something is iterable) and is not subjected just to js Arrays.
With Map, the situation is more complicated. Unlike with List, the destructuring of Map-like structures IS subjected just to plain JS objects and nothing more. Currently, it does not seem that ES community considers this a good idea (see https://esdiscuss.org/topic/extensible-destructuring-proposal)
However, there exist babel-plugin that enables this: https://github.com/vacuumlabs/babel-plugin-extensible-destructuring
Having this plugin installed and enabled in .babelrc, you can simply patch immutable Map to have a .##get method defined:
// main.js, first file loaded
import {Iterable} from 'immutable';
Iterable.prototype[Symbol.for('get')] = function(value) {return this.get(value); };
and everything works (also nested destructuring, or destructuring with default values)
import {fromJS} from 'immutable';
const map = fromJS({author: {name: {first: "John", last: "Doe"}, birthdate: "10-10-2010"}});
const {author: {name: {first, last}, birthdate}} = map;
Disclaimer: I'm one of the authors of the plugin mentioned above.

Related

How to take some data from an object?

I have to put data from json file to my reducer.
And after mapping this file I got an object which includes data that I need.
export const datas = data.properties.map(data => (<store key={Math.floor(Math.random()*1234)} author={data.value} comment={data.group} rate={data.type} />));
this is console log, I just need props from this
How to get just normall react-table, not an object which is not accepting by reducer state?
Or how to implement it to reducer state to get effect that I need?
I am sorry for stupid questions, I hope you will help me :)
The code which you posted takes an array of objects from a variable data.properties and maps them to an array of JSX elements created by the component store. Perhaps it is better readable with line breaks.
export const datas = data.properties.map(
data => (
<store
key={Math.floor(Math.random() * 1234)}
author={data.value}
comment={data.group}
rate={data.type}
/>
)
);
Your console.log of datas shows that array of React JSX element instances. In your array you have 5 objects which are each a JSX element ($$typeof: Symbol(react.element)) with type: "store" (the component type), the numeric key that you created for this element, and a props object which contains all of the props that you passed: author, comment, and rate (key is a special prop so it is not included here).
You are asking to just create an object with the props rather than creating a store element. We want to take the array data.properties and use the .map() method to map it to this props object.
The variable name that you use inside of your .map() callback can be anything, but as a best practice I recommend that you should not use the variable name data again. Reusing a name is called variable shadowing and it won't cause errors, but it can make your code very confusing. I will call it datum instead.
Here is the code that you want:
export const propsArray = data.properties.map(
datum => ({
key: Math.floor(Math.random() * 1234),
author: datum.value,
comment: datum.group,
rate: datum.type,
})
);

Reducing the size of a JSON object array by stripping unwanted object attributes

One of our end point is returning a JSON object array. Each object in the array has 10 attributes originally. In order to keep the array in state, I'm thinking of rebuilding the JSON array with object with minimum attribute (I need only 2).
Is there an elegant way to do this ES6 (Currently I'm using some loops)
Whether the reduction in size can gain me in terms of performance (react application and I'm supposed to store the lighter JSON in state)
Thanks,
San
Use the array map function, following is a bare minimum (ES6) example,
const data = [
{foo: 'foo_value_a', bar: 'bar_value_a', baz: 'baz_value_a'},
{foo: 'foo_value_b', bar: 'bar_value_b', baz: 'baz_value_b'},
{foo: 'foo_value_c', bar: 'bar_value_c', baz: 'baz_value_c'},
]
const compactData = data.map(({foo, bar}) => ({foo, bar}));
compactData now contains only objects with foo and bar and it reads like this, for each object of data destructure foo and bar and return a new object shaped with just these two properties.
The old school way (ES5) translates to
const compactData = data.map(function(d) {
return {foo: d.foo, bar: d.bar };
});
Rule of thumb when you have an array of objects and you want the same amount of objects but with different shape you think of map!!!

ES6 Set does not serialize to array

I've noticed that the Set in ES2015 does not implement a simple toJSON function, such as serializing to an array. Below is the implementation I came up with that does just that:
Object.defineProperty(Set.prototype, 'toJSON', {
enumerable: false,
value: function () {
return [...this];
}
});
Is there any reason why a Set does not serialize to an array?
Are there any edge cases where this override for toJSON is a bad idea?
See this answer as to why there can't be a general toJSON case for Maps, and for similar reasons, Sets. Basically, keys and/or Set items can be anything, including objects and references to other things that can't be serialized into JSON (which, remember, is a specific format with specific, stricter rules than just "turn into intelligible data of another type"). What you want here is more like "toArray" anyhow. You method already works for that inline, as would Array.from(Set), I think.
But if you wanted to add this sort of method to the prototype for your own internal usage without risking possible problems if a similar (but not identical) method is ever added, you could use a Symbol key'd prop.
var toArray = Symbol('toArray');
Object.defineProperty(Set.prototype, toArray, {
enumerable: false,
value: function () {
return [...this];
}
});
var g = new Set();
g.add(9);
g[toArray]();//-> [9]
If you do that, then you are guaranteed to not cause problems with anything other than your own code, since only your code will have access to the toArray Symbol key that references that method.

Is there a way to "grep" for a keyword in a JavaScript object in Chrome Dev Tools?

I often work with large JavaScript objects and instead of manually opening and closing "branches", I would like to simply search for a particular string and show any key or value that matches.
Sort of like "grepping" for a keyword in a JavaScript object. Is this possible (especially in Chrome Dev Tool)?
Unfortunately I was hoping I could at least try the JSON.stringify() trick and then search on the raw JSON in a text editor, but I get the following error:
Uncaught TypeError: Converting circular structure to JSON
You can look at the object's keys and match against them:
function grepKeys(o, query){
var ret = {};
Object.keys(o).filter(function(key){
return key.includes(query);
}).forEach(function(key){ // can reduce instead
ret[key] = o[key]; // copy over
});
return ret;
}
Which'd let you return a partial object with all the keys that contain the string you specified. Note that this will not show any prototype keys but can be easily extended to allow it (by using a for... in instead of an Object.keys or by using recursion):
var o = grepKeys({buzz:5, fuzz:3, foo:4}, "zz");
o; // Object {buzz: 5, fuzz: 3}

d3.js forced layout graph: parse String to link-array

I am referring to this example: http://bl.ocks.org/mbostock/1153292 ,
specifically to these beautiful lines of code:
var links = [
{source: "Microsoft", target: "Amazon", type: "licensing"},
...
{source: "Nokia", target: "Qualcomm", type: "suit"}
];
var nodes = {};
// Compute the distinct nodes from the links.
links.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});
I'd like to know what data format 'var links' here has, and how I would parse the following java string (with essentially the same content)
String someLinks = "[{source: \"Microsoft\", target: ... }, ...]"
into something equal to the javascript 'var links' above, from which I can then create the graph.
I've tried
var links = JSON.parse( string );
But that doesn't do the job... 'var links' doesn't seem to be JSON?
EDIT: Or should I use a different java format, e.g. some kind of Array? (Doesn't have to be a String)
Your value in String someLinks is no valid JSON. It lacks the quotes on the attribute names. JSON is more pedantic than javascript itself.
JSON.parse('[{"source":"A"},{"source":"B"}]')
will work (note the " around source.
Also you should avoid writing "protocols" by hand. If you need to build a JSON string in javascript, you can use
JSON.stringify([{source:'A'},{source:'B'}])
Note that JSON e.g. also escapes / for security reasons. An oversight like this can quickly end in errors or worse.
I believe this is JSON in a string. Since JSON is simply JavaScript, you might be able to simply "run" the code to create the corresponding data structure. So try
var links = eval(someLinks)
Even though I have the suspicion if we take a step back, things might be handled differently and you wouldn't need eval in the first place (since it's generally considered bad style)