Muirik
Muirik

Reputation: 6289

Using spread operator to avoid mutating state in React function

In my React project I have a function within a class-based component that handles video uploads. It is working as expected and desired. However, I realized upon inspection that it violates React's don't mutate state mandate. I think that's the case, though I want to ensure that's true, and that the solution I've come up with deals with this.

Here is my component state:

  state = {
    streamingRes: {},
    uploadFailed: false
  }

My initial function looked like this (notice there are 3 places where I am setting the state):

  fileUploadHandler = (id, file, fileId) => {
    const isValid = this.validateVideoFileType(file);
    if(!isValid) this.props.showError(`${file.name} is of the wrong file type (${file.type}).  File must be an acceptable video format.`);

    let dataStream = io.Stream.createStream();

    io.Socket.on('userVideos.uploadProgress', (data) => {
      this.setState( { streamingRes: data });
      if(fileId === data.data.guid) {
        this.uploadCompletionPercentage = data.data.progress;
      } 
    });

    io.Stream(io.Socket).emit('userVideos.upload', dataStream, {
      guid: fileId,
      size: file.size
    }, (data) => {
      if(data.status === "failure") {
        this.props.onUploadFailed();
        this.setState( { uploadFailed: true })
      }
      else if(data.status === "success") {
        this.props.upload(id)
      }
    });

    this.setState( { uploadFailed: false });

    io.Stream.createBlobReadStream(file).pipe(dataStream);
    return;
  }

To avoid mutating state I updated this function to look like this:

  handleFileUpload = (id, file, fileId) => {
    let newState = {...this.state};
    const isValid = this.validateVideoFileType(file);
    if(!isValid) this.props.showError(`${file.name} is of the wrong file type (${file.type}).  File must be an acceptable video format.`);

    let dataStream = io.Stream.createStream();

    io.Socket.on('userVideos.uploadProgress', (data) => {
      this.setState( { streamingRes: data });
      if(fileId === data.data.guid) {
        this.uploadCompletionPercentage = data.data.progress;
      } 
    });

    io.Stream(io.Socket).emit('userVideos.upload', dataStream, {
      guid: fileId,
      size: file.size
    }, (data) => {
      if(data.status === "failure") {
        this.props.onUploadFailed();
        newState.uploadFailed = true;
        this.setState( { uploadFailed: newState.uploadFailed });
      }
      else if(data.status === "success") {
        this.props.upload(id)
      }
    });

    newState.uploadFailed = false;
    this.setState( { uploadFailed: newState.uploadFailed });

    io.Stream.createBlobReadStream(file).pipe(dataStream);
    return;
  }

Notice I am using the spread operator right at the top of the function now. My question is: does this effectively deal with the issue of avoiding state mutation?

Upvotes: 0

Views: 210

Answers (1)

Sulthan
Sulthan

Reputation: 130102

Yes, you have avoided mutating state. However, your way of doing it is completely unnecessary because there is no need to copy the state into a new object if you don't use that object.

Instead of:

newState.uploadFailed = true;
this.setState( { uploadFailed: newState.uploadFailed });

You can simply do:

this.setState({ uploadFailed: false });

There was no problem in your code in the first place.

Upvotes: 1

Related Questions