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;
}, [])
}
Related
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>
+
€ <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>+€ <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.
I just want to understand is the usage of .map() inside reducers makes them non-pure? I clearly understand that pure functions is the functions that always return predictable (lets say dirty - "the same") result. But I think that usage of .map() inside reducer makes result non-predictable, because it lets him go ahead by one of two ways in ternary operation, that is a non-puse function way. So, just look on my reducer code and say is I'm wrong or not?
Thank you! )
// .. reducer
[SELECT_CDS]: (state, action) => ({
...state,
crimesByType: state.crim.map(
(cri, i) =>
i === 0
? {
...cri,
additionalInfo: {
...cri.addition,
CDsLeft: true
}
}
: crime
)
})
A reducer should be pure function, meaning that if the reducer is called twice with the same input, the output should also be the same.
In your case, the reducer is pure, because even though your map() and ternary operator give different results for different elements of the array, the final result will always be the same if the original array and action are the same.
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})] )
);
I've been reading about different methods to avoid mutating the state. One of those methods is using spread operators (...) and one of the methods to avoid using is push. However in my reducer I need to add an item to an array inside a nested structure , I couldn´t implement concat correctly so I tried the following code:
export default function (state=[],action){
if (action.type === 'SELECTED_DROP') {
let updated = [ ...state];
updated[action.payload.queryIndex].items.push(action.payload.item) ;
return updated;
}
return state;
}
So, I am using both: spread operator and push. Am I mutating the state?
Thank You
Yes, you are mutating the state. From what I gather your state is an array with objects containing a property items which is also an array. You are modifying the items array and so you are mutating the state.
Here's what you should do:
export default function (state=[], action) {
switch (action.type) {
case 'SELECTED_DROP':
return state.map((item,ix) =>
ix===action.payload.queryIndex ?
{...item, items:[...item.items, action.payload.item]} :
item
);
case default:
return state;
}
}
The map function basically returns the old item if not changed or a new item with a new items array if it's the correct index.
Yep, you absolutely are. You're making a shallow copy of the top-level array, but directly mutating the inner array.
There are two basic rules of immutably updating data:
Every level of nesting needs to have a copy made
You can use mutation, but only if you're mutating the actual copy
In this case, you need to make copies of the top array, the item at that index, and the items array itself. Nested updates can get kind of ugly, but that's the way it is.
I have links to a number of articles on how to properly write immutable update code at react-redux-links, and links to a number of utility libraries for abstracting out those updates at react-redux-links & Immutable Update Utilities .
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.