最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Object.assign is modifying original array object - Stack Overflow

programmeradmin0浏览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
  }
]

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
Add a ment  | 

5 Answers 5

Reset to default 2
const 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;
发布评论

评论列表(0)

  1. 暂无评论