Reputation: 6040
What would be the recommended way to display a rapidly changing value in React, e.g upload progress? In my axios config I have
onUploadProgress: progressEvent => {
let percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total )
this.setState({ avatarUploadPercentage: percentCompleted })
}
<span>Upload progress: {this.state.avatarUploadProgress}</span>
but setState
doesn't like being called that quickly of course, and won't guarantee order. Should I use refs instead and change the inner html myself?
Upvotes: 9
Views: 5307
Reputation: 3198
What do you want to do with the value of avatarUploadPercentage
? If you need to display the actual number, then as suggested in the other answer you could either debounce setState or modify the dom directly.
However if it's displaying a progress bar being filled, it could be done using CSS, although still modifying the element via ref, but not triggering a whole component lifecycle (wasteful)
Something like
[refToProgressBarElement].style.width = `${avatarUploadPercentage}%`
Upvotes: 0
Reputation: 354
How about limiting when the onUploadProgress
callback runs? You can wrap your callback in a "debounce" function which limits the frequency a callback will run. Underscore and Lodash offer debounce methods.
Once per second:
onUploadProgress: debounce(progressEvent => {
let percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total )
this.setState({ avatarUploadPercentage: percentCompleted })
}, 1000)
See plain debounce function from https://davidwalsh.name/javascript-debounce-function.
Upvotes: 4
Reputation: 2462
I'd recommend using a ref to access the element that is displaying the progress. Calling setState for that case is a bit wasteful on the rendering side if it's just a progress bar/value that is changing. Call setState when the upload begins to display progress, then setState again to hide it after it's complete.
Upvotes: 3