0

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?

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

So you're saying my initial implementation wasn't mutating state?
@Muirik Not at all. Mutating state would be for example this.state.uploadFailed = false. Mutating state is generally a problem when your state contains objects, not simple values, e.g. if you tried mutating progressResponse without copying the value first.
@Muirik What if find more problematic is this.uploadCompletionPercentage which obviously somehow mutates the component without using state of props.
Yes, I see that now. It was because I was misunderstanding the mutating state issue. I will update accordingly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.