how to setState all element of list of states - javascript

I have an array of string names and i want to do bellow
let accountcode:{a:1,b:2};
let array=["first","second",third];
this.setState({[array[0]:accountCode,array[1]:accountCode,array[3]:accountCode]})
but array is dynamic list and i should map in array and setState every item of it in one setState
i try
object.setState(
{...stateName:accountCodes}
)
but not working and i also try below and not throw syntax error:
object.setState(
stateName.map(s=>{[s]=accountCodes})
)
what should i do?

You could use the reduce function to achieve it. Each iteration in your array will add the element to your object with a computed property :
const accountcode = { a: 1, b: 2 };
const array = ["first","second","third"];
this.setState(array.reduce((acc, val) => ({[val]: accountcode, ...acc}), {}));
Working example :
class App extends React.Component {
componentDidMount(){
const accountcode = { a: 1, b: 2 };
const array = ["first", "second", "third"];
this.setState(array.reduce((acc, val) => ({ [val]: accountcode, ...acc }), {}));
}
render(){
console.log(this.state)
return <div></div>
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.1/umd/react-dom.production.min.js"></script>
<div id='root'>

You're looking at creating an object from an array. The question is just a rephrase of creating an object from an array.
In your case, the solution may be as follows:
let accountCode = {a: 1, b: 2};
let array = [1, 2, 3, 4];
let output = {};
for (let key of array) {
output[key] = accountCode;
}
// Almost forgot this
this.setState(output);

You can simply write something like this:
let accountCode = {a:1, b:2};
let array = ["first", "second", "third"];
/* Function in which you will call setState */
let newState = {};
array.forEach(el => {
newState[el] = accountCode;
});
Though, I suggest you to not simply write newState[el] = accountCode; otherwise you are using the same Object for each property of newState. You could write newState[el] = JSON.parse(JSON.stringify(accountCode)); to prevent that!

Related

I need to wrap each element of an array even the children elements, I'm working with JavaScript

I need to wrap each element of an array, even elements of the children.
input:
var array = [
{"name":"name1"},
{"name":"name2"},
{"name":"name3", children : [{"id":"1"}]}];
Desired output:
var newArray = [
{elem : {"name":"name1"}},
{elem : {"name":"name2"}},
{elem : {"name":"name3", children : [{elem : {"id":"1"}}]}}];
I have done the following:
function insertKey(array){
for (var i = 0; i<array.length; i++){
tempItem = {elem : array[i]}
newarray.push(tempItem);
}
}
// Output:
newarray =
[{elem:{"name":"name1"}},
{elem:{"name":"name2"}},
{elem:{"name":"name3"}}]
But the problem comes when it contains children. I tried the below but its not working.
function insertKey(array){
for (var i = 0; i<array.length; i++){
tempItem = {elem : array[i]}
newarray.push(tempItem);
insertKey(array[i]);
}
}
Thanks in advance.
To do this for any level of nesting, we can use a fairly simple recursive approach:
const transform = (xs) =>
xs .map (({children, ...rest}) => ({
elem: {
...rest,
...(children ? {children: transform (children)} : {})
}
}))
But I think one level of abstraction improves this significantly. If we separate the bit that wraps a node in an {elem: ...} structure from the bit that recursively applies that, our code is both simpler and more reusable. Its concerns are better separated. So I would probably write it like this:
const mapDeep = (fn) => (xs) =>
xs .map (({children, ...rest}) => fn ({
...rest,
...(children ? {children: mapDeep (fn) (children)} : {})
}))
const data = [
{name:"name1"},
{name:"name2"},
{name:"name3", children : [
{id: "1"},
{id: "2", children: [ {foo: "bar"}, {foo: "baz"} ]}
]}
]
const wrapInElem = (node) => ({elem: node})
console .log (mapDeep (wrapInElem) (data))
And of course by passing only the function to mapDeep, we get a reusable function that does what you want:
const transform = mapDeep (wrapInElem)
// or, using an anonymous function instead
// const transform = mapDeep (node => ({elem: node}))
// ...
transform (data)
you can try iterating over each object of array and adding them to new array. That gives the output that you desire.
define the function as:
-
function f(array){
newArray=[]
for(i of array){
newArray.push({elem:i})
}
return newArray
}
var array = [
{"name":"name1"},
{"name":"name2"},
{"name":"name3", children : [{"id":"1"}]}];
newArray=f(array)
console.log(newArray)
Sounds like you want something like this:
function insertKey(array) {
const newarray = [];
for (let i = 0; i < array.length; i++) {
const tempItem = {elem : array[i]};
if (array[i].children) {
tempItem.children = array[i].children.map(child => ({elem: child}));
}
newarray.push(tempItem);
}
return newarray;
}
The new conditional maps each child and wraps it like you described. You'll use this like so:
const newarray = insertKey(array);
Edit: Note that this solution only works for one level of nesting. If you needed it to go deeper, your question (as stated) doesn't give us enough information to help, because we don't know the schema of the data that you're trying to wrap.

What does 3 dots actually do here

I saw a react component that has the state showed below:
class MyComp extends BaseComponent {
constructor(props) {
super(props);
this.state = {
selectedColumns: [],
params: {
offset: 0,
sort_by: {}
}
}
...
}
}
Then this react component has a method getValue below. Inside this method allParams object is created by using spread syntax. I.e. it is spreading methods argument params, and after that updates params object in components state.
getValue(params){
const allParams = {
...this.state.params,
...params
}
this.setState((prevState) => {
return {
...prevState,
params: allParams
}
})
...
}
It is then called like below in a child component inside MyComp:
goNext() {
const offset = 15 // IT IS NOT JSON, it is a value 15.
this.props.getValue({
offset
})
}
I see that setState is ok but is allParams creation correct? Must not the params be an object (json) to be used with ...? Am i missing something?
In other cases the spread syntax is used like this:
const ob1 = {foo: 123};
const ob2 = {bar: 234};
const merged = {...ob1, ...ob2};
console.log(merged) //Output: { foo: 123, bar: 234 }
But in my case it would be:
const ob1 = {foo: 123};
const ob2 = 15;
const merged = {...ob1, ...ob2};
console.log(merged) //Output: { foo: 123}, and ob2 is not assigned!
The ES6 spread operator can be used on Objects to 'spread' their values into another object to create a clone of that object. It is similar in concept to using Object.assign
Sample
const x = { a : 1 };
const y = {...x}; // y = {a:1} Equivalent to : const y = Object.assign({},x);
const z = {...x , b: 2} // z = {a:1,b:2} Equivalent to Object.assign({a:1},{b:2})
const w = {...x , a: 2} // w = {a:2} Equivalent to Object.assign({a:1},{a:2})
const p = {a:2, ...x} // p={a:1} Equivalent to using Object.assign({a:2},{a:1})
Handy link explaining this in the context of Redux
EDIT: Based on discussion in comments:
In your goNext method, when this happens:
this.props.getValue({
offset
})
You are actually creating an object like this {offset:15}. So when this is used in getValue like:
const allParams = {
...this.state.params,
...params
}
You are essentially overriding the old offset value with 15 and creating a new object. So essentially, we are NOT spreading over 15 but over {offset:15}

React destructuring applied in a native JS project

I'm going through a React + Redux tutorial where there is a code snippet such as this:
class ExampleComponent extends Component {
constructor() {
super();
this.state = {
articles: [
{ title: "React Redux Tutorial for Beginners", id: 1 },
{ title: "Redux e React: cos'è Redux e come usarlo con React", id: 2 }
]
};
}
render() {
const { articles } = this.state;
return <ul>{articles.map(el => <li key={el.id}>{el.title}</li>)}</ul>;
}
}
Then, out of curiosity I did a simillar thing but in a non-react environment (eg. in console log in the browser). First I initialized a constant like this:
const articles = [
{ title: "React Redux Tutorial for Beginners", id: 1 },
{ title: "Redux e React: cos'è Redux e come usarlo con React", id: 2 }
]
But what confuses me is the destructuring part after which I get undefined. Like this:
const { someObj } = articles;
undefined
someObj
undefined
{ someObj }
{someObj: undefined}
someObj.title
VM205:1 Uncaught TypeError: Cannot read property 'title' of undefined
at <anonymous>:1:9
My question is, why const { articles } = this.state; works fine, but const { someObj } = articles; returns undefined?
You are trying in the wrong way. You have an object here and it has an array:
const obj = { arr: [ 1, 2, 3 ] };
Instead of using like obj.arr you are destructuring the arr like that:
const { arr } = obj;
And use that variable directly with its name as arr.
If you want to destructure any item from an array you can use array destructring:
const [ number1, number2, number3 ] = arr;
If you want to combine those steps:
const { arr: [ number1, number2, number3 ] } = obj;
So right side is the destructured variable and the left side is the variables that you are destructring from the original one.
Also see:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Because this.state is an Object, and your articles variable is an Array.
Object destructing syntax:
const { var1, var2 } = obj;
is equal to
const var1 = obj.var1;
const var2 = obj.var2;
Array destructing syntax:
const [arr1, arr2, ...arr3] = arr;
is equal to
const arr1 = arr[0];
const arr2 = arr[1];
const arr3 = arr.slice(2);
You can see more here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

modify a property of an object in the functional way

In javascript programming in the functional way is a great benefit. I'm trying to modify a property of an object contained in an array of objects in the functional way that means that the item that is the object passed in the map function cannot be modified. If I do something like this:
const modObjects = objects.map((item) => {
item.foo = "foo" + 3;
return item;
});
this is not functional because item is modified inside the function. do you know any other approach to this problem?
A new (ES6) way that is really immutable and in the spirit of functional programming:
// A. Map function that sets obj[prop] to a fixed value
const propSet = prop => value => obj => ({...obj, [prop]: value})
// B. Map function that modifies obj.foo2 only if it exists
const foo2Modify = obj =>
obj.hasOwnProperty('foo2') ? {...obj, foo2: 'foo ' + obj.foo2} : obj
// Usage examples of A and B
const initialData = [{'foo': 'one'}, {'foo2': 'two'}, {'foo3': 'three'}]
const newData1 = initialData.map(propSet('foo2')('bar')) // Set value
const newData2 = initialData.map(foo2Modify) // Use a modify function
console.log(initialData) // Initial data should not change
console.log(newData1) // Each object should contain the new fixed foo2
console.log(newData2) // Modify foo2 only if it exists in initial data
You could use Object.assign to create a copy of the item obj and return that from the map callback.
Object.assign()
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
Here is an example
let data = [
{"foo": "one"},
{"foo": "two"},
{"foo": "three"}
]
let newData = data.map( item => {
let itemCopy = Object.assign({}, item);
itemCopy.foo = "foo " + item.foo;
return itemCopy;
})
console.log(data)
console.log(newData)
You can also do it like this:
const modObjects = objects.map((item) => {
return { ...objects, foo: "foo" + 3; };
});
The reason that this: objects.map((item) => { ...destSchema, foo: "foo" + 3; }); doesn't work is that they made it this way to make the JS interpreter understand whether it is a scope or an object. You MUST use return
In modern JavaScript you can use spread operator on object inside of an object literal for this:
const modObjects = objects.map(
item => ({...item, foo: item.foo + 3})
)
Notice parentheses () around object literal. They are needed to disambiguate object literal {} from code block {} in lambdas. Another way is to use code block with return:
const modObjects = objects.map(
item => { return {...item, foo: item.foo + 3} }
)
I have extended #Dimitrios Tsalkakis answer to change property with a callback function.
Example: https://repl.it/#robie2011/ts-set-property-functional
Typescript:
function mapProperty<T>(prop: string){
return (cb: (propValue: any) => any) => (obj: any) => ({...obj, [prop]: cb(obj[prop])}) as (T)
}

Can one set multiple properties inside an object literal to the same value?

For example, can I do this?:
{
a: b: c: d: 1,
e: 2,
geh: function() { alert("Hi!") }
}
EDIT:
Is there some way I can avoid doing this?:
{
a: 1,
b: 1,
c: 1,
d: 1,
e: 2,
geh: function() { alert("Hi!") }
}
An update to this (in terms of the latest JavaScript abilities) avoiding unwanted defined vars:
{
let v;
var obj = {
"a": (v = 'some value'),
"b": v,
"c": v
};
}
This will mean v won't be defined outside the block, but obj will be.
Original answer
Another way of doing the same thing is:
var v;
var obj = {
"a": (v = 'some value'),
"b": v,
"c": v
};
You could set a line of equality between various properties:
var foo = {};
foo.a = foo.b = foo.c = "Hello";
Or you could just create a method that does the mass-assignment for you:
var foo = {
setValue: function( props, value ) {
while ( props.length ) this[ props.pop() ] = value;
}
}
foo.setValue( [ "a", "b", "c" ] , "Foo" );
You could try this. It's not the syntactic sugar you're looking for (eg. {a,b,c:1, d:2}) but it's another way to do it, although all of these answers are pretty much fine.
(object,fields,value)=>Object.assign(object||{}, ...fields.map(f=>({[f]:value}) ))
Explanation:
(object,fields,value)=>
Takes an object (or falsey value if you want a new object, feel free to rearrange the argument order)
Object.assign(object||{},
Will return an object based on object and it will mutate the object. To disable this, simply add a first argument object literal like this Object.assign({}, object || {}, ...
...fields.map(f=>({[f]:value}) )
Will spread the array of fields mapped to objects as a list of extra arguments to Object.assign. ['a','b'].map(f=>({[f]:value}) ) will give [{a:value}, {b:value}] and f(...[{a:1},{b:1}]) is like f({a:1},{b:1}). Object.assign does the rest :)
There's yet another approach: using a mapping function...
// This will be standard!
if (!Object.fromEntries)
Object.fromEntries = entries => entries.reduce ((o, [key, value]) => ({
...o,
[key]: value
}), {})
const setSameValue = (source, props, value) => ({
...source,
...Object.fromEntries (
props.map (prop => [prop, value])
)
})
// The important part: do what you want with ease!
const output = setSameValue ({}, ['1', '01'], 'string 1')
const obj = { x: 1, y: 'hello' }
const output2 = setSameValue (obj, ['1', '01'], 'string1')
console.log ('output1:', output)
console.log ('output2:', output2)
You could wrap in a closure too, if you didn't want multiple local vars. This syntax seems to be popular (but ugly):
var obj = (function() { var v='some value'; return { a:v, b:v, c:v }; })();
Use for of loop instead.
for (let [key, value] of Object.entries(object_name)) {
object_name[key] = 0; // the value that you want to assign
}
Or yet another way:
{...['a', 'b', 'c', 'd'].reduce((obj,prop)=>({...obj, [prop]: 1}), {}) }
It can be wrapped up pretty neatly by extending the Array prototype:
Array.prototype.ditto = function(v) { return this.reduce((o,p)=>({...o, [p]: v}), {}) }
So now it can be used like this:
{
...['a', 'b', 'c', 'd'].ditto(1),
...['e', 'f'].ditto(2)
geh: function() { alert("Hi!") }
}
Explanation: the .reduce starts off with an empty object {} and for each element prop return an object which is whatever was in the object already ...obj plus a new property with our value 1: [prop]: 1. Then expand these properties into the outer object with the ... at the start.
If you had tons of properties reduce wouldn't be the most efficient, but you could change it to:
Array.prototype.ditto = function(v) { let o = {}; this.forEach(p => o[p] = v); return o; }
More readable and more efficient but less cool??

Categories

Resources