Holden1515
Holden1515

Reputation: 699

Copying React State object; modifying copied object changes state object

I am trying to copy a state object:

@boundMethod
private _onClickDeleteAttachment(attachmentName: string): void {
    console.log("_onClickDeleteAttachment | this.state.requestApproval[strings.Attachments]: ", this.state.requestApproval[strings.Attachments]);

    let requestApprovalClone = {... this.state.requestApproval}

    if (requestApprovalClone === this.state.requestApproval) {
        console.log("they are ===");
    }
    else {
        console.log(" they are not ===");
    }

    _.remove(requestApprovalClone[strings.Attachments], (attachment: any) => {
        return attachment.FileName === attachmentName;
    })

    console.log("_onClickDeleteAttachment | this.state.requestApproval[strings.Attachments]: ", this.state.requestApproval[strings.Attachments]);
    console.log("_onClickDeleteAttachment | requestApprovalClone[strings.Attachments]: ", requestApprovalClone[strings.Attachments]);
}

enter image description here

The state object is being altered too. From what I have read, I shouldn't mutate a state object but only change it with setState.

How can I correct this?

Upvotes: 7

Views: 14421

Answers (3)

G43beli
G43beli

Reputation: 3962

It has to to with the way that JS handles their const references.

For those who feel adventerous:

let requestApprovalClone = JSON.parse(JSON.stringify(this.state.requestApproval));

// modify requestApprovalClone ...

this.setState({
  requestApproval:requestApprovalClone
})

It would be interesting if Object.assign({},this.state.requestApproval); is faster than the whole JSON stringify/parse stuff or vice versa

Upvotes: 5

Deepak
Deepak

Reputation: 870

You can have something like:

let requestApprovalClone = Object.assign({},this.state.requestApproval);

requestApprovalClone.strings.Attachments = requestApprovalClone.strings.Attachments.slice(); // will create a shallow copy of this array as well

_.remove(requestApprovalClone[strings.Attachments], (attachment: any) => {
        return attachment.FileName === attachmentName;
    })

this.setState({
  requestApproval:requestApprovalClone
})// If you want to update that in state back

Upvotes: 1

Abdelkarim EL AMEL
Abdelkarim EL AMEL

Reputation: 1533

You are getting that behavior, because the

let requestApprovalClone = {... this.state.requestApproval}

is only shallow copying the data, your attachments property has some nested objects and it keeps the same reference and therefore when changing it, the cloned object gets altered and the state too.

To avoid that, you can perform another copy of your attachments property like this :

let attachments = [...requestApprovalClone[strings.Attachments]];
_.remove(attachments, function (attachment)  {
  return attachment.FileName === attachmentName;
});

Changing the attachments variable content won't afftect the state anymore.

you can read more about that behavior here

Upvotes: 8

Related Questions