Casper Jacobsen
Casper Jacobsen

Reputation: 45

Copying and not referencing state object in REACT

Trying to create a copy of a state object, change it, and then set it using setState().

However, I can't copy the object, and instead it creates a reference. Meaning when I edit it, I edit the state object directly, which means setState() doesn't rerender, since nothing actually changed from when I edit the object, to when I try and run setState().

I have been able to do this with an array, which is including in my code below.

// This is my state
interface IEditPanelState {
    currentFiles: SearchResults;
    newFiles: File[];
}


// This is my function
   public async cacheFiles(files: File[]) {
        // This works
        let cachedFiles = [...this.state.newFiles];
        // This is creating a reference. How to copy Searchresults??
        let currentFiles = this.state.currentFiles;
    
        for(let file of files) {
          cachedFiles.push(file);
          currentFiles.PrimarySearchResults.push({
            Title: file.name
          });
        }

        console.log(currentFiles);
        console.log(cachedFiles);
        console.log(this.state.newFiles);

        this.setState({
            newFiles: cachedFiles,
            currentFiles: currentFiles
        });
   } 

Upvotes: 0

Views: 3222

Answers (2)

Casper Jacobsen
Casper Jacobsen

Reputation: 45

This has been answered by @SarangPM as a comment.

Here's the answer:

let currentFiles = this.state.currentFiles; will always create a reference. For a shallow copy, you can use the spread operator and for a deep clone, you can use deep clone function from lodash.

I Installed lodash, had some problems, but ended up fixing it. Check my comment below.

I just installed it using npm. It says to import using: import { _ } from 'lodash'; However this results in the following error: '_' can only be imported by turning on the 'esModuleInterop' flag and using a default import. EDIT: nvm, I got it working using: import { cloneDeep } from 'lodash';

So thanks to @SarangPM for answering my question, and solving my problem. I'm adding this as an answer, since @SarangPM didn't.

EDIT: Please read the answer from @jaybhatt, since using DeepClone isn't optimal

Upvotes: -1

jaybhatt
jaybhatt

Reputation: 547

Can you explain the primary need behind having to do a deep clone of the state? It might not be performant in case the array size grows and may also be unnecessary.

Also, as your new state is dependent upon the previous state, it might help if you go with the functional convention there. Something like below


// this has the logic to extract current files from present state
const getCurrentFiles = (currState) => { ... };

const cacheFiles = (files) => {
  this.setState((currentState) => {
    const currentFiles = getCurrentFiles(currentState);
    return ({
      newFiles: [...currState.currentFiles, ...files],
      currentFiles
    });
  })
}

Link to Documentation for setState functional convention - setState documentation

Upvotes: 1

Related Questions