DEV Community

Cover image for Audio Player with Wavesurfer.js & React πŸ„πŸ½β€β™‚οΈ
andy_801 πŸ”«πŸ‡ΊπŸ‡¦
andy_801 πŸ”«πŸ‡ΊπŸ‡¦

Posted on

Audio Player with Wavesurfer.js & React πŸ„πŸ½β€β™‚οΈ

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 });
Enter fullscreen mode Exit fullscreen mode

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} />;
Enter fullscreen mode Exit fullscreen mode

🐟 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]);
Enter fullscreen mode Exit fullscreen mode

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]);
Enter fullscreen mode Exit fullscreen mode

🦦 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();
});
Enter fullscreen mode Exit fullscreen mode

Top comments (6)

Collapse
 
hrghafoori profile image
HamidReza Ghafoori

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?

Collapse
 
librien profile image
Kevin

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.

Collapse
 
typosbro profile image
Azizbek Umidjonov

I suppose you could convert your files into blob and bind to HTML.

Collapse
 
feelzz profile image
Peter Fields

Thanks for creating this article. It was useful.

Collapse
 
ankitkataria9 profile image
Ankit Kataria

Hi. I am having memory leak when multiple instances of wavesurfer created. I am creating them in a React Component.

Collapse
 
biomathcode profile image
Pratik sharma

you might have forgotten to add any dependencies in the useEffect components