I am having a issue in reactjs state management .Everytime component loaded it loads the data from cache.I done research over that and found that state is immutable.I want to ask how to use immute the state.
Currently it is like i took a empty array in state in constructor then I called a api in component will mount and set that state to response but untill and unless Indont clear cache, state is not showing the data
Guide me where I am making mistake here or how can I immute the state
Mutating an object: Use the Object.assign({}, ...)
var yourCar = {
color: 'red',
.. the same as neighboursCar
};
var neighboursCar = {
color: 'red',
... the same as yourCar
};
yourCar.color = 'blue'; // reference stays the same!
var yourCarRepainted = Object.assign({}, yourCar, { color: 'blue' });
yourCarRepainted === yourCar; // false
Mutating an array: Use [].concat
var list = [1, 2, 3];
var list = [1, 2, 3];
list[1] = 4;
var list = [1, 2, 3];
var changedList = [].concat(list);
changedList[1] = 4;
var list = [1, 2, 3];
var changedList = [].concat(list);
changedList[1] = 2;
list === changedList; // false
this.state and this.setState({}) in React is already immutable.
You can also try immutable.js 3rd party library to get a better grasp on this subject.
Related
you need to add new values to the array, I can't understand what the problem is.
When you click on a checkbox, you need to get the id of this checkbox and write it to the array of answers for the corresponding question
type Result = number;
interface Answer {
result: Result[];
}
const answers: Answer[] = [];
questions.forEach(() => {
answers.push({
result: [],
});
});
const [currentAnswer, setNewAnswer] = useState<Answer[]>(answers)
const handleChange = (e:React.ChangeEvent<HTMLInputElement>) =>{
// console.log(typeof(currentAnswer),currentAnswer);
if(e.target.checked){
console.log(currentAnswer[currentQuestion].result.push(Number(e.target.id)));
setNewAnswer(
currentAnswer[currentQuestion].result.push(Number(e.target.id) // ERROR HERE
)
...
I got error
const currentAnswer: Answer[]
// Argument of type 'number' is not assignable to parameter of type 'SetStateAction<Answer[]>'
should use .concat() in this situation to return new array
.push() will only return new length which is number and incompatible with the type you make.
setNewAnswer(
currentAnswer[currentQuestion].result.concat(Number(e.target.id)) // ERROR HERE
)
To expand on Mic Fung's answer, push mutates the existing array and doesn't return the new array.
const myArray = [1, 2, 3]
myArray.push(4) // returns 4, which is the new array length
console.log(myArray) // [1, 2, 3, 4]
concat doesn't mutate the existing array, but instead returns a new array
const myArray = [1, 2, 3]
const myNewArray = myArray.concat(4)
console.log(myNewArray) // [1, 2, 3, 4]
console.log(myArray) // [1, 2, 3]
When working with React, you should avoid directly mutating the state. Instead, create new values and pass them to the setState function. This is why functions like concat are preferred over ones like push, as they avoid the mutation.
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.
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)
Goal: I have two square and I want to change selected square's location. While I'm doing it, I need to change selected square's x-coordinate, y-coordinate, width, and height.
Here is my state which holds the data for square information.
state = {
gestureState: {},
thumbSize: 100,
left: width(100) / 2,
top: height(100) / 2,
taggedClothes: {
0: {id:0, left:100, top:100, thumbSize:100}, <- I want to setState this
1: {id:1, left:200, top:200, thumbSize:200},
},
selectedClothId : 0,
}
Problem: taggedClothes have two square information and I want to change only selected problem but I'm getting compile error
Here I'm performing setState its taggedClothes[0]
// this.state.selectedColorId = 0
var deep = _.cloneDeep(this.state.taggedClothes[this.state.selectedColorId]);
deep.left = left
deep.top = top
deep.thumbSize = thumbSize
this.setState({
gestureState: {
...gestureState
},
taggedClothes[0]: deep <- Getting Compile Error
})
If your have any other suggestion, Please suggest other option!
The key taggedClothes[0] is not valid. You need to spread the taggedClothes and only replace the one that changed:
var deep = _.cloneDeep(this.state.taggedClothes[this.state.selectedColorId]);
deep.left = left
deep.top = top
deep.thumbSize = thumbSize
this.setState({
gestureState: {
...gestureState
},
taggedClothes: {
...taggedClothes,
[this.state.selectedColorId]: deep
}
})
You are trying to access your taggedClothes object like an array.
change this:
taggedClothes: {
0: {id:0, left:100, top:100, thumbSize:100}, <- I want to setState this
1: {id:1, left:200, top:200, thumbSize:200},
},
to that:
taggedClothes: [
{id:0, left:100, top:100, thumbSize:100},
{id:1, left:200, top:200, thumbSize:200},
],
now you should be able to access taggedClothes.
I have a Flux Store and a state array that needs updating when a new comment is created so that a list of comments updates in the view. I just want to confirm that I am updating it correctly using push:
this.state.comments.push(commentArray);
It works fine but I have read about immutability but as this is a store and not a view I take it this is ok?
onDispatcherAction: function (payload) {
var action = payload.action;
if (ActionTypes.CREATE_CONFIGURATION_SETTINGS_RESPONSE === action.type) {
this.handleResponseErrors(action.data);
var commentArray = {
_id: action.data._id,
user: {
id: action.data.user.id
},
id:action.data.id,
commentname: action.data.commentname,
timeCreated: action.data.timeCreated
}
this.state.commentname = action.data.commentname;
this.state.comments.push(commentArray);
this.emitChange();
}
}
You probably should take a look to the Immutability Helpers.
From React Documentation
Simple push
var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
initialArray is still [1, 2, 3].