I'm trying to modify a property value of a specific index in my state this property is the post_ments
But my problem is the state is being modified even though i am only modifying the copy of it.. The code works how i want it to be but i'm modifying the state so it's probably bad how do i fix this?
socket.on('statusComment', (data) => {
const mutator = Object.assign([], this.state.getStatus);
const index = mutator.findIndex(i => i._id === data._id);
mutator[index].post_ments = data.post_ments; // Replace old post_ments with data.post_ments
console.log(mutator) // Got the post_ments
console.log(this.state.getStatus) // Also modified
// Commented out setState
// this.setState({
// getStatus: mutator
// })
});
Here is a sample data
detected by socket
const data = {
post_id: "5b0689f03fb2fd1404f1854d",
post_ments: [{text: 'what'}]
}
This is what my state looks like
const data_arr = [
{
"post_img": [],
"post_date": "2018-05-24T09:46:24.948Z",
"post_ments": [
{
"ment_posted": "2018-05-24T09:46:31.015Z",
"_id": "5b0689f73fb2fd1404f1854e",
"ment_from": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"ment_text": "kaka2"
},
{
"ment_posted": "2018-05-24T09:47:42.752Z",
"_id": "5b068a3e2fdd6f141d5ba995",
"ment_from": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"ment_text": "kaka!"
}
],
"_id": "5b0689f03fb2fd1404f1854d",
"post_description": "get out\r\n",
"post_by": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"__v": 2
}
]
Spread operator is not working logs the same thing with the Object.assign
method
// console.log(mutator)
[
{
"post_img": [],
"_id": "5b0694cc7925c914e4d95dda",
"post_description": "test",
"post_by": {
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo",
"photo_url": "png"
},
"post_ments": [
{
"_id": "5b0694d67925c914e4d95ddb",
"ment_from": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"ment_text": "This ment should only be in the mutator ",
"ment_posted": "2018-05-24T10:32:54.937Z"
}
],
"post_date": "2018-05-24T10:32:44.613Z",
"__v": 0
}
]
// console.log(this.state.getStatus);
[
{
"post_img": [],
"_id": "5b0694cc7925c914e4d95dda",
"post_description": "test",
"post_by": {
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo",
"photo_url": "png"
},
"post_ments": [
{
"_id": "5b0694d67925c914e4d95ddb",
"ment_from": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"ment_text": "This ment should only be in the mutator ",
"ment_posted": "2018-05-24T10:32:54.937Z"
}
],
"post_date": "2018-05-24T10:32:44.613Z",
"__v": 0
}
]
I'm trying to modify a property value of a specific index in my state this property is the post_ments
But my problem is the state is being modified even though i am only modifying the copy of it.. The code works how i want it to be but i'm modifying the state so it's probably bad how do i fix this?
socket.on('statusComment', (data) => {
const mutator = Object.assign([], this.state.getStatus);
const index = mutator.findIndex(i => i._id === data._id);
mutator[index].post_ments = data.post_ments; // Replace old post_ments with data.post_ments
console.log(mutator) // Got the post_ments
console.log(this.state.getStatus) // Also modified
// Commented out setState
// this.setState({
// getStatus: mutator
// })
});
Here is a sample data
detected by socket
const data = {
post_id: "5b0689f03fb2fd1404f1854d",
post_ments: [{text: 'what'}]
}
This is what my state looks like
const data_arr = [
{
"post_img": [],
"post_date": "2018-05-24T09:46:24.948Z",
"post_ments": [
{
"ment_posted": "2018-05-24T09:46:31.015Z",
"_id": "5b0689f73fb2fd1404f1854e",
"ment_from": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"ment_text": "kaka2"
},
{
"ment_posted": "2018-05-24T09:47:42.752Z",
"_id": "5b068a3e2fdd6f141d5ba995",
"ment_from": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"ment_text": "kaka!"
}
],
"_id": "5b0689f03fb2fd1404f1854d",
"post_description": "get out\r\n",
"post_by": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"__v": 2
}
]
Spread operator is not working logs the same thing with the Object.assign
method
// console.log(mutator)
[
{
"post_img": [],
"_id": "5b0694cc7925c914e4d95dda",
"post_description": "test",
"post_by": {
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo",
"photo_url": "png"
},
"post_ments": [
{
"_id": "5b0694d67925c914e4d95ddb",
"ment_from": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"ment_text": "This ment should only be in the mutator ",
"ment_posted": "2018-05-24T10:32:54.937Z"
}
],
"post_date": "2018-05-24T10:32:44.613Z",
"__v": 0
}
]
// console.log(this.state.getStatus);
[
{
"post_img": [],
"_id": "5b0694cc7925c914e4d95dda",
"post_description": "test",
"post_by": {
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo",
"photo_url": "png"
},
"post_ments": [
{
"_id": "5b0694d67925c914e4d95ddb",
"ment_from": {
"photo_url": "png",
"_id": "5af16d60f3957c11e46500ae",
"display_name": "Lumpo"
},
"ment_text": "This ment should only be in the mutator ",
"ment_posted": "2018-05-24T10:32:54.937Z"
}
],
"post_date": "2018-05-24T10:32:44.613Z",
"__v": 0
}
]
Share
Improve this question
edited May 24, 2018 at 10:34
markus paterson
asked May 24, 2018 at 10:19
markus patersonmarkus paterson
472 silver badges5 bronze badges
5 Answers
Reset to default 2const mutator = Object.assign([], this.state.getStatus);
its doing shallow/reference
copy of array.
So,original array is copied as it is using reference.
Use spread operator
to create new copy of array and then do JSON.stringify followed by JSON.parse.U need a deep copy.
let mutator = [...this.state.getStatus];
mutator = JSON.parse(JSON.stringify(mutator));
you can copy your array something like this :
const mutator = [...this.state.getStatus];
Object.assign([], this.state.getStatus)
[]
is an array, not an object. This is likely causing a problem.
Edit: See Josh’s ment, it is an object, but also an array. But the behaviour will be different to if it were an object object.
The quickest way to make a copy of an existing array without copying a reference is the following:
const mutator = this.state.getStatus.slice(0);
as described here https://developer.mozilla/de/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
Your state is an object containing an array of objects.
First you copy state and reset the array getStatus
with getStatus
mapped. When the status item is found that needs to change you copy that item but set post_ments with another value (see code below).
this.setState({
...this.state,//copy state
getStatus: this.state.getStatus.map(//getStatus is a new array
(item,index)=>
(item._id===data._id)//if item._id is data._id
? {...item,post_ments:data.post_ments}//copy item but reset post_ments
: item//not the item we are looking for, return item (not changed copy)
)
})
If you need more help the please let me know.
Using JSON.parse(JSON.stringify(state)))
will cause all ponents to re render even if their part of the state did not change (deep copy versus shallow copy). You can use shouldComponentUpdate
to see if the state actually changed and tell react not to re render ponents where this did not happen. However; since you are deep copying everything (not only the items that changed) you cannot do this.
Here is an example of a base ponent that checks if the state passed to it actually changed reference and should re render:
import React from 'react';
class OnlyIfChanged extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return nextProps.state !== this.props.state;
}
}
export default OnlyIfChanged;