Recently I was in need to set a simple view that can show audio file waveform and play its audio using React.JS. After some googling, I found this Wavesurfer.js package. It has pretty exciting use examples, except it lucks of React.JS example, which as we know lives in its own virtual world, what force you write code in its specific way. So, I share my example here with some main points.
Here is the final result (with some soundcloud-like style)
Code In Details
π Reference to DOM
We can import package and use the module as usual.
import WaveSurfer from "wavesurfer.js";
WaveSurfer.create({ container: someDiv });
Most tricky things happen when React rerenders component replacing DOM elements and old ones lost. WaveSurfer.js
doesn't expect these changes, so we need to provide an alias to a needed HTML element within React.
We can do it setting ref
to some element and passing this ref
to WaveSurfer object on creating.
const waveformRef = useRef(null);
useEffect(() => {
WaveSurfer.create({
container: waveformRef.current
});
}, []);
return <div ref={waveformRef} />;
π Reference to Audio Player
A similar thing we need to do to access Wavesurfer instance from our React component. Again, because of React nature, on each rerender React component born in a new body (function) and it doesn't have access to variables from previous live. So we need to save it between rerenders with similar ref
technique.
const wavesurfer = useRef(null);
useEffect(() => {
wavesurfer.current = WaveSurfer.create(options);
// Removes events, elements and disconnects Web Audio nodes.
// when component unmount
return () => wavesurfer.current.destroy();
}, [url]);
And, when component life is over or when we want to create a new instance we need to destroy the previous one manually, otherwise, you will have multiply copies displayed on the screen and you won't have access to them.
Lastly, at this stage, we need to destroy the old instance and create a new one each time we will have url
property changed. Based on docs, looks like you can use the same instance over-and-over, but for me, it wasn't updated properly so I did it this way.
useEffect(() => {
...
}, [url]);
𦦠That's all.
That is actually all you need to do specific to React - Wavesurfer.js communication. Next, you can follow Wavesurfer.js docs on how to use it. For example:
wavesurfer.current.load(url);
wavesurfer.current.on("ready", function() {
// https://wavesurfer-js.org/docs/methods.html
wavesurfer.current.setVolume(0.5);
wavesurfer.current.play();
});
Top comments (6)
I want to have an audio player on my website, but the important thing is that users should not be able to download that audio. Does this library have the ability to keep the sound source secret? If not, can you recommend a library or solution to do this for me?
If users really wanted to get the audio, they will. You could prohibit them from accessing the file to download directly via the server but they could still record using software. Perhaps you could include an audio watermark.
I suppose you could convert your files into blob and bind to HTML.
Thanks for creating this article. It was useful.
Hi. I am having memory leak when multiple instances of wavesurfer created. I am creating them in a React Component.
you might have forgotten to add any dependencies in the useEffect components