K20GH
K20GH

Reputation: 6281

Modifying & Duplicating File Object in React

I have a component in React where I pass it a file object. I do various things with this File object, but I am also adding new values to the File object by doing this.props.file.color = #000

Within my component, I have a function that triggers a parent function to duplicate the File Object

Component

duplicate =()=> {
    this.props.file.color = this.getColor();
    console.log(this.props.file)
    //File Object
    // -- color: #cb0000
    // -- name:filename.png
    this.props.duplicate(this.props.file);
}

As you can see, it has added a color value to the File Object, and the filename is correct. I then pass this data back to a duplication function in my parent

Parent

i is the array index, a is the File Object

  duplicate(i, a) {
    let dupeArr = a;
    const arr = [...this.state.files];

    const index = i + 1;
    let name = dupeArr.name.slice(0, -4);
    Object.defineProperty(dupeArr, 'name', { writeable: true, value: `${name}-${a.color}.png`})

    arr.splice(index, 0, a);
    console.log(arr)
    // 2x File Objects
    // Original file
    // -- #cb0000 (Correct)
    // -- filename-#cb0000.png (Incorrect, why is it changing this name?)
    //Duplicated file
    // -- -- #cb0000 (Correct)
    // -- filename-#cb0000.png (Correct)
    this.setState({
      files: arr
    })
  }

What I am doing here is taking the File Object that was passed to it, defining the name of that File Object and then splicing into the existing files array before setting it as state.

For some reason though, when I define the name property, it is changing the name in both the original entry in the array, as well as my new File Object.

Any suggestions?

Upvotes: 1

Views: 1189

Answers (2)

deowk
deowk

Reputation: 4318

The reason is that you are mutating the original file object, and it is still being referenced in this.state.files. You are making a copy of your files array here:

const arr = [...this.state.files];

But this does not in fact produce copies of the file objects contained in the array. They are still referencing the original objects.

You are running into issues because you are mutating the file object at this line and your copied array is still referencing the original object:

Object.defineProperty(dupeArr, 'name', { writeable: true, value: `${name}-${a.color}.png`})

Assuming you are converting the File object to a normal JS Object (like you mentioned in your answer) and then only passing the index of the object you want to modify to duplicate:

duplicate = (index) => {
  let filesCopy = [...this.state.files];
  let objToModify = filesCopy[index];
  let objModified = {...objToModify, name: /* somename */, preview: /* some preview */ }

  filesCopy.push(objToModify);

  this.setState({ files: filesCopy });
}

Upvotes: 1

K20GH
K20GH

Reputation: 6281

The problem was that when the files were uploaded, the were File Objects and it is not possible to copy a File Object.

The easy solution was to take @deowk's duplication solution, but also to convert the File Objects to a JSON Object on upload, only taking what I needed:

  onDrop(files) {
    let f = files.map(file => ({
      name: file.name,
      preview: file.preview
    }));

        this.setState({
            files: this.state.files.length > 0 ? [...this.state.files, ...f] : f,
        });
  }

Upvotes: 1

Related Questions