Why when I change copy of object in TS, original one also changes? - reactjs

I'm importing redux store and using the spread operator to create a copy of store property. Then when I change this copy, the original property also changes.
When I use copy = JSON.parse(JSON.stringify(original)) everything works fine.
export const move = (moveData: IMove): BoardActionTypes => {
const { board } = store.getState();
console.log(board.pieces.byId["19"]); // {row: 3, col: 7}
const newById: IPiecesById = { ...board.pieces.byId };
newById["19"].col = 4;
newById["19"].row = 4;
console.log(board.pieces.byId["19"]); // {row: 4, col: 4}
console.log(newById["19"]); // {row: 4, col: 4}
//...
};

Your issue is about shallow VS deep copy of an object.
When using spread operator, your creating a shallow copy of an object (Just like when using old-school Object.assign).
When you've used JSON parsing - you get a deep copy (or a "deep clone") of the object.
Shallow copy, as the name suggest, means that the outer object is a new one, while nested objects remains the same. Once you get to know redux in-depth, speard operators should be suffice for most cases, but it is an important difference to keep in mind.
You might want to read my question on this matter, and this article as well,.

I have 2 options for it.
1. Using underscore.js
var foo = { row: 0, col:0 };
var bar = _.clone(foo);
bar.row = 99;
console.log(foo);
console.log(bar);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore.js"></script>
2. vanilla JS
function clone(obj) {
if (obj === null || typeof(obj) !== 'object')
return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) {
copy[attr] = obj[attr];
}
}
return copy;
}
var foo = { row: 0, col: 0 };
var bar = clone(foo);
bar.row = 99;
console.log(foo);
console.log(bar);

What happens to you is - two objects with the same reference.
If you don't want to use an external lib, or a helper function (if you're not going to use it extensively), you can use something like this:
const newById = board.pieces.byId.map((item) => ({ ...item }));
(i assumed byId is an array, and map creates new array)

Related

Update a specific variable of a useState array (by its place) in React.js?

In my React.js functional component, I need to update only one of the variable of a useState array:
let [nums, setNums] = React.useState([0,0,0])
to this:
let [nums, setNums] = React.useState([0,1,0])
without changing the other variables (something like: setNums(nums[1] = 1)).
Is that possible?
Thanks!
Maybe use index of the element in the array.
const handleChange = (targetIndex)=>{
setState(nums.map(element, index) => if(targetIndex === index){ return updated;} return element);
}
You can create a shallow copy using spread syntax and set new value using index on the copied array:
const update = (index, value) => {
const copy = [...nums] // Create a copy
copy[index] = value // Set new value
setNums(copy)
}
Note that above method is not mutating the original data. A demo:
const nums = [0, 0, 0]
const copy = [...nums]
copy[1] = 100
console.log(nums, copy)
PS: Using map() function is not really required in this case because we already know which index value should be updated.

why add curly braces to the argument 'people' here [duplicate]

I have been reading about Destructuring assignment introduced in ES6.
What is the purpose of this syntax, why was it introduced, and what are some examples of how it might be used in practice?
What is destructuring assignment ?
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
- MDN
Advantages
A. Makes code concise and more readable.
B. We can easily avoid repeated destructing expression.
Some use cases
1. To get values in variable from Objects,array
let obj = { 'a': 1,'b': {'b1': '1.1'}}
let {a,b,b:{b1}} = obj
console.log('a--> ' + a, '\nb--> ', b, '\nb1---> ', b1)
let obj2 = { foo: 'foo' };
let { foo: newVarName } = obj2;
console.log(newVarName);
let arr = [1, 2, 3, 4, 5]
let [first, second, ...rest] = arr
console.log(first, '\n', second, '\n', rest)
// Nested extraction is possible too:
let obj3 = { foo: { bar: 'bar' } };
let { foo: { bar } } = obj3;
console.log(bar);
2. To combine an array at any place with another array.
let arr = [2,3,4,5]
let newArr = [0,1,...arr,6,7]
console.log(newArr)
3. To change only desired property in an object
let arr = [{a:1, b:2, c:3},{a:4, b:5, c:6},{a:7, b:8, c:9}]
let op = arr.map( ( {a,...rest}, index) => ({...rest,a:index+10}))
console.log(op)
4. To create a shallow copy of objects
let obj = {a:1,b:2,c:3}
let newObj = {...obj}
newObj.a = 'new Obj a'
console.log('Original Object', obj)
console.log('Shallow copied Object', newObj)
5. To extract values from parameters into standalone variables
// Object destructuring:
const fn = ({ prop }) => {
console.log(prop);
};
fn({ prop: 'foo' });
console.log('------------------');
// Array destructuring:
const fn2 = ([item1, item2]) => {
console.log(item1);
console.log(item2);
};
fn2(['bar', 'baz']);
console.log('------------------');
// Assigning default values to destructured properties:
const fn3 = ({ foo="defaultFooVal", bar }) => {
console.log(foo, bar);
};
fn3({ bar: 'bar' });
6. To get dynamic keys value from object
let obj = {a:1,b:2,c:3}
let key = 'c'
let {[key]:value} = obj
console.log(value)
7. To build an object from other object with some default values
let obj = {a:1,b:2,c:3}
let newObj = (({d=4,...rest} = obj), {d,...rest})
console.log(newObj)
8. To swap values
const b = [1, 2, 3, 4];
[b[0], b[2]] = [b[2], b[0]]; // swap index 0 and 2
console.log(b);
9. To get a subset of an object
9.1 subset of an object:
const obj = {a:1, b:2, c:3},
subset = (({a, c}) => ({a, c}))(obj); // credit to Ivan N for this function
console.log(subset);
9.2 To get a subset of an object using comma operator and destructuring:
const object = { a: 5, b: 6, c: 7 };
const picked = ({a,c}=object, {a,c})
console.log(picked); // { a: 5, c: 7 }
10. To do array to object conversion:
const arr = ["2019", "09", "02"],
date = (([year, day, month]) => ({year, month, day}))(arr);
console.log(date);
11. To set default values in function. (Read this answer for more info )
function someName(element, input,settings={i:"#1d252c", i2:"#fff",...input}){
console.log(settings.i)
console.log(settings.i2)
}
someName('hello', {i:'#123'})
someName('hello', {i2:'#123'})
12. To get properties such as length from an array, function name, number of arguments etc.
let arr = [1,2,3,4,5];
let {length} = arr;
console.log(length);
let func = function dummyFunc(a,b,c) {
return 'A B and C';
}
let {name, length:funcLen} = func;
console.log(name, funcLen);
It is something like what you have can be extracted with the same variable name
The destructuring assignment is a JavaScript expression that makes it possible to unpack values from arrays or properties from objects into distinct variables. Let's get the month values from an array using destructuring assignment
var [one, two, three] = ['orange', 'mango', 'banana'];
console.log(one); // "orange"
console.log(two); // "mango"
console.log(three); // "banana"
and you can get user properties of an object using destructuring assignment,
var {name, age} = {name: 'John', age: 32};
console.log(name); // John
console.log(age); // 32
The De-structured assignment of Javascript is probably an inspiration drawn from Perl language.
This facilitates reuse by avoid writing getter methods or wrapper functions.
One best example that I found very helpful in particular was on reusing functions that return more data than what is required.
If there is a function that returns a list or an array or a json, and we are interested in only the first item of the list or array or json,
then we can simply use the de-structured assignment instead of writing a new wrapper function to extract the interesting data item.

Why the spread operator will directly affect the state and sometime it doesn't? (React) [duplicate]

This question already has answers here:
Does Spreading create shallow copy?
(3 answers)
Closed 2 years ago.
I'm new to reactJS, however there is something that confuses me like why when I copy a simple object using the spread operator and modify its content, the object in the state is not affected. However, if I create a copy of an array using the same way and changes its content then the object in the state is now modified as reflected to what has been done to the copy.
class App extends Component {
state = {
value: { id: 5, count: 0 },
};
sampleFunction = () => {
let sampleValue = { ...this.state.value };
sampleValue.count--;
console.log(this.state.value.count);
console.log(sampleValue.count);
};
componentDidMount() {
// Ajax Call
console.log("App - Mounted");
this.sampleFunction();
}
}
result : 0 -1
class App extends Component {
state = {
value: [{ id: 5, count: 0 }],
};
sampleFunction = () => {
let sampleValue = [...this.state.value];
sampleValue[0].count--;
console.log(this.state.value[0].count);
console.log(sampleValue.[0]count);
};
componentDidMount() {
// Ajax Call
console.log("App - Mounted");
this.sampleFunction();
}
}
result : -1 -1
what is the concept behind this?
In the former case, the spread syntax creates a shallow copy of the the this.state.value object. sampleValue is an independent object with its own count value.
// new object with independent count property
let sampleValue = { ...this.state.value };
In the latter case, the spread syntax creates a new array, but the array's entries point at the same objects that are in the original. Modifications to those objects are reflected in both places because they are the same objects.
// new array, but contains the original objects
// sampleValue[0] and this.state.value[0] are literally the same object
let sampleValue = [...this.state.value];
You can see this concretely in the following example:
const someObject = { bananas: 1, wookies: 3};
// two arrays containing the same object
const firstArr = [someObject];
const secondArr = [someObject];
firstArr[0].bananas = 4; // modifies the shared object
console.log(secondArr[0].bananas); // 4
someObject.wookies = 42; // modifies the shared object
console.log(firstArr[0].wookies); // 42
console.log(secondArr[0].wookies); // 42

Retrieve the Object values and assign it to Another one Object in ReactJS

I have to retrieve an object and assign it to another one. But in the new object, always the last item only stored.
I tried object.entries keys method but nothing worked.
code : https://codesandbox.io/s/k3p7j07x8o
let subject = {};
const obj = { a: 5, b: 4, c: 9 };
for (const [key, value] of Object.entries(obj)) {
console.log(`${key} ${value}`);
//console.log(subject); // Here itself it's printing the last element
subject.value = key;
subject.text = value;
console.log(subject.value + subject.text); // This showing the correct element
console.log(subject); // This one showing the last elements
}
You can use this syntax:
let subject = Object.assign({}, obj}
console.log(subject)
or
let subject = {};
Object.assign(subject, obj);
console.log(subject)

setState in react js, with ES6 destructuring

I have this react code which set the state::
onMoveUp={(ids: SelectedIdMap) => {
this.setState({
xyz: {
...this.state.xyz,
[tt]: [
...this.state.xyz[tt].filter(a => (a.id in ids)),
...this.state.xyz[tt].filter(a => !(a.id in ids)),
],
},
});
}}
This code changes the index of passed array element (ids) to the top of array.
Current state is like this::
{"51f6c052-b218-45ce-b3db-c9b95249e03a":[{"id":"11553dc4-d194-476c-9e05-aaac28ea3e76","prediction":"India–Japan relations","confidence":1},{"id":"3f76ce1d-a821-4418-a332-3285176ae456","prediction":"Japan Democratic Party (1954) politicians","confidence":1},{"id":"031d3913-984a-4af7-aaa3-73e23c206ff1","prediction":"Japan–Taiwan relations","confidence":1}]}
I am unable to understand what [tt] means in this code & how it is updated.
ids = 11553dc4-d194-476c-9e05-aaac28ea3e76 in the parameter.
It is silly question but please help me understand it.
This is nothing but Computed property name concept in js. That means we can use any valid js expression to compute the property name at run time.
As per MDN Doc:
Starting with ECMAScript 2015, the object initializer syntax also
supports computed property names. That allows you to put an expression
in brackets [], that will be computed and used as the property name.
This is reminiscent of the bracket notation of the property accessor
syntax.
Its helpful to write a reusable code instead of hardcoding the values.
Check this snippet:
var obj = {"1234": 1, "3412": 2},
a = "34", b = "12";
var newObj = {
[a+b]: obj[a+b],
[b+a]: obj[b+a],
[10+20+30]: 60
}
console.log('newObj = ', newObj);
Check this snippet how its working in your case:
var obj = {"a": 1, "b": 2};
function update(key, value){
return {[key]: value};
}
obj = Object.assign({}, obj, update('a', 10));
obj = Object.assign({}, obj, update('b', 20));
console.log('bj = ', obj);

Resources