I’m using this wavesurfer.js
package with React for display wave form of audio. I want to display the current elapsed time using this getCurrentTime()
method in their docs and answer here on github.
I got the elapsed time in seconds and update my React state to display it. However, it updates quite frequently, more than 10 times per second which trigger my component to re-render multiple times. I wonder if there is a way to make it only trigger state changes on each seconds pass?
export function Component(){
const [currentTime, setCurrentTime] = useState(0)
const wavesurferRef = useRef<any>(null)
useEffect(()=>{
if (wavesurferRef.current){
wavesurferRef.current.on('audioprocess', function () {
//ISSUE: THIS MAKE COMPONENT RE-RENDERING TOO MANY TIME
setCurrentTime(wavesurferRef.current.getCurrentTime())
})
}
},[])
return(
<div ref={wavesurferRef}>
</div>
)
}
3
Answers
Since in my application, I only need the value in seconds, so I use this simple approach to
Math.floor
the value andsetState()
, causesetState
only change the state if the value is different, therefore, the component will just be re-rendered every seconds.The general answer is you need to NOT call
setCurrentTime
on every event.More practically you can either use some custom logic to define which events to skip. Or you can use generic helper functions to do so. If you want your function to not be called more often than every N ms it is call
throttle
. You can use lodash or other utility libraries for thathttps://lodash.com/docs/4.17.15#throttle
Live example https://laracasts.com/series/build-modern-laravel-apps-using-inertia-js/episodes/22
I might suggest you
useRef
with a DOM node and something like requestAnimationFrame to update the text. Here’s a minimal, verifiable example. Run the program below and notice a render only happens when you click the button and update the state. The timestamp is updated using animation instead of state transition –