Is this object destructuring or something else? - destructuring

I'm analyzing code and realized that I can't understand exactly part of it. Please help me with it
import {someOffers} from "../const.js";
const createOffer = () => {
const offers = someOffers.map(({name, price}) => `<li class="some__offer">
<span class="some__offer-title">${name}</span>
&plus;
€ <span class="some__offer-price">${price}</span>
</li>`);
return offers;
}
I understand that:
We import array someOffers from const.js. This is a 7-elements array of objects with 3 keys in each (name, price, type).
We create arrow function to create the same length offers array (as someOffers) of template literals markup with appropriate keys (name, price) for each element. It is done by map() method, which changes each element of the array using the function, written in parameters:
(({name, price}) => <li class="some__offer"><span class="some__offer-title">${name}</span>&plus;€ <span class="some__offer-price">${price}</span></li>)
Can you please decipher these parameters for me. Especially the ones in object literals. Does it has to do something with destructuring?
Thanks!

Yes, it's destructuring the elements inside someOffers.
You could do this for example:
someOffers.map(offer => <div>${offer.name} ${offer.price}</div>)
or
someOffers.map(({name, price}) => <div>${name} ${price}</div>)
Hopefully this illustration helps picture what's going on.

Related

Unable to iterate keys of a map in es6 in list comprehension style due to keys is not a function error

I want to be able to convert a map in javascript into an immutable data structure.
I have the following structure in a map written in es6
const features = {
'BASIC': [
'BASIC',
'STANDARD',
],
'SUPER' : [
'OK',
'MORE',
],
}
Each value of the map will be used to initialise a class called Detail. At the end an immutable map will be created to mimic the structure of this features variable.
This is my first cut:
const data = Immutable.Map(features.keys()(key) => {
const details = features[key];
return [key, new Details({details})];
}
));
I intended to use entries() because it is only available in es7.
However the browser (chrome Version 56.0.2924.87 (64-bit)) does not like this syntax and throw features.keys is not a function.
However according to documentation on MDN, I expect this function to exist.
Eventually if I use Object.keys, it seems to work:
const data = Immutable.Map(Object.keys(features).map(key) => {
const details = features[key];
return [key, new Details({details})];
}
));
But it becomes rather verbose.
Is there anyway I can make it simpler and more elegant? I hope it can be done in a python-like style. (something like [k, v] for k, v in features.items())
It's probably about as simple as can currently be done. JavaScript doesn't have Python-like list comprehensions, either in the language or an active proposal. (They were considered for ES 2015 (ES6), but were cut before its completion and haven't so far returned for newer editions.)
I intended to use entries() because it is only available in es7.
Since you mentioned using Chrome 56, Object.entries() has been available for use since Chrome 54. Firefox and Safari also include it in recent versions. And, for other browsers without it, the proposal for it includes a small polyfill.
With it, you won't save many characters, but you can take advantage of destructured assignment in the iterator's parameters to get key and details.
const data = Immutable.Map(Object.entries(features)
.map( ( [key, details] ) => [key, new Detals({details})] )
);

Iterating through keys of Immutable Map in React

What is a good practice for handling iteration through an Immutable.js Map object? This works:
{stocks.map((stock,key)=>{
return ( <h3>{key}</h3> )
})}
but gives the warning in the console "warning.js:45 Warning: Using Maps as children is not yet fully supported. It is an experimental feature that might be removed. Convert it to a sequence / iterable of keyed ReactElements instead."
This has been discussed before, and this link suggests some strategies https://github.com/facebook/immutable-js/issues/667 but they seem clunky to me. Like:
posts.entrySeq().map(o =>
<Post value={o[1]} key={o[0]} />
)
works but is clunky feeling. Is there a more natural way of doing this?
Since you asked this question, a better solution has been posted on the github issue you reference. #vinnymac suggests:
posts.entrySeq().map( ([key, value]) =>
<Post key={key} value={value} />
)
this works well because entrySeq() returns a Sequence of key/value tuples, which you can then destructure in the params of the .map() callback.
edit I see now that you are only asking for the keys. In that case use keySeq() if you want to use ImmutableJS map() or keys() if you want to use ES6 map()
Why not stock.keys()? As it returns an ES6 iterator, you'll need to cast it to an array for it to work in older JS versions: Array.from(stock.keys())
let zoo = Immutable.fromJS({ 'dog': 1, 'cat': 2 })
zoo.keys().map((name, index) => <Animal name={ name } key={ index } />)
Notice that I avoided key as a variable and then passed the index value as key to the children component, this is because react needs references to dynamically created components so it can handle them correctly within its VirtualDOM. Read more about React's Dynamic Children.
Using Immutable Map's reduce method is a more direct approach. Since react expects an array so setting initial value of empty array and pushing jsx into it solves the issue. Works for immutable List as well.
{
stocks.reduce((jsxArray, stock, index) => {
jsxArray.push(
<h3 key={index}>{index}</h3>,
)
return jsxArray;
}, [])
}

How do I type a function with input and output objects with the same keys but different value types?

Basically, I have a function that will transform an object into a different object, and it's like a dictionary, but I don't know how to type it.
var myFunctions = {
a: () => something1,
b: () => something2,
[...]
}
gets transformed into
var myObject = {
a: something1,
b: something2
[...]
}
With Flow 0.33+ you can use $ObjMap
type ExtractCodomain = <V>(v: () => V) => V;
declare function f<O>(o: O): $ObjMap<O, ExtractCodomain>;
I don't think you can do this with Flow. The closest you can get is probably this:
function<T>(obj: T): ([key: $Keys<T>]: boolean)
That function is typed to return an object with the same key as input object, but with boolean-only values (as an example, you can specify another type). Sorry to disappoint, but it's hard to type highly dynamic code with Flow in general.
Note that the $Keys feature is undocumented because it's not part of the public API, so its behavior is defined solely by its implementation (in other words, it can change anytime).
If you're interested in the details of Flow's type system, check out the typings that come with flow in its own /lib directory, for example https://github.com/facebook/flow/blob/master/lib/core.js – you'll see that some things like Object.assign are special-cased, so you might not be able to re-implement such things in your own code.
Also, check out http://sitr.us/2015/05/31/advanced-features-in-flow.html for other "dollar features" such as $Shape and $Diff – it's partially outdated, but can give some good pointers.
#Nikita gave you the best answer for now. That said, the use-case you talked about is being discussed in the issues on the FlowType repository. It may land soon.
As of right now, if you've got mixed type, I'll just fallback to any
function<T>(obj: T): ([key: $Keys<T>]: any)
This way, at least the key names are validated. I expect within a few more versions of Flow, this problem will get solved.

Forget doesn't work

If I try to remove an item from this collection
$examples = Example::where('example', '=', $data['example'])->get();
by doing
$examples->forget(20);
it doesn't remove the item from the collection, I still get back all the items that were in there originally. I have read the Laravel documentation and the api docs. And it should work (I think) but it doesn't.
Could someone point me out what I am doing wrong here?
This still returns an object.
$examples->forget(49);
return $examples->find(49);
P.S. Ever other method like push or get works.
Thanks alot!
You did a small mistake, actually you didn't notice that. I did myself :).
Forget use the array key to delete an object item from collection.
Array(0 => 'abc'
1 => 'bcd'
49 => 'aaa'
)
$examples->forget(49);
^^ array key 49
Where as, find use the id to find an object from an collection
table: examples
id example
1 abc
49 bce
$examples->find(49);
^^ `example id`
According to the documentation it says that forget() works by key. The word "key" is ambiguous because what they mean to say is array key also known as "index" and not model key which is the id.
However, in the other methods such as find() or contains() they use the word "key" to mean model key so you can see the confusion.
When you look at the source you can see that the forget() method is found in the Illuminate\Support\Collection class and not in Illuminate\Database\Eloquent\Collection.
My theory is that the support class is supposed to be more generic so it doesn't consider the model keys, but really I don't know.
I just wanted to add on to the Anam's answer. Once you have a collection you can then loop through it like this to delete by ID
function forgetById($collection,$id){
foreach($collection as $key => $item){
if($item->id == $id){
$collection->forget($key);
break;
}
}
return $collection;
}
$examples = Example::where('example', '=', $data['example'])->get();
$examples = forgetById($examples,20);
you could do
$examples->reject(20);
Like most other collection methods, reject returns a new collection instance; it does not modify the collection it is called on.

What is the equivalent of foreach (with keys) in ActionScript

I am looking for the equivalent of a foreach loop with keys in Actionscript. In PHP this would be:
foreach($array as $key => $value)
{
}
I found two solutions that will work, but I am wondering if there is a better way to do this. The first solution is to use the for..in loop. Which gives you the keys, but you still have to use the key to access the correct element in your structure. For example:
for(var key:String in results)
{
trace(key + ": " + results[key]);
}
The second option is the for each..in loop, which I believe is new in AS3. With this solution, I can't tell what the keys are. For example:
for each(var row:* in results)
{
trace(row);
}
For the time being, I am going to use for..in. I am just looking for a better way.
Thanks,
Rob
Update: Speed is not a huge deal, because the array is never going to be extremely large. Order does matter, and I would like to get keys in the order of insertion. Here is an example of the array:
sites = {'site1': 34, 'site2': 52, 'site3': 66}
I would like to use the key as well as the value of each entry.
I want to keep my array structure as simple as possible. I could change the sites array above to look like:
sites = {{'name': 'site1', 'id': 34},
{'name': 'site2', 'id': 52},
{'name': 'site3', 'id': 66}}
However, I would rather not go this route, because it adds more dimensions to my array structure.
It depends on your object type. If you're using a Dictionary, you have:
DictionaryUtil.getKeys(myObject)
I wouldn't use for...in unless you're just dumping or purely want the keys and nothing else. It is an object so sort isn't guaranteed and will vary. If sorting isn't an issue, this (for...in or dictionary) is your best bet.
Grant speaks more on dictionary here: http://www.gskinner.com/blog/archives/2006/07/as3_dictionary.html.
for(var i:String in myArray) // loops through the items in the array
myArry[i] += 'new message will show'
for each(var i:String in myArray) // creates a copy of the array as it loops
myArray[i] += 'this change will not show outside the loop';
The later is great for if you need to minipulate the variables during the loop but want to preserve the original object for the rest of your program. Especially handy for formatting or translating values for a specific part of your program.

Resources