1

I have been getting an inconsistent error popping up while interacting with controls my audio player using wavesurfer.js.

Here is the error:

cannot read properties of null (reading 'isPaused')

I'm not sure but i think it is to do with the way i have the wavesurfer import inside my useEffect. This was the only way i could get the wavesurfer container to render correctly without throwing a different error.

Here is my component:

import { useSelector } from "react-redux";
import { useEffect } from "react";
import { useState } from "react";
import styles from "../../styles/audioPlayer.module.css";

let WaveSurfer = null;

const AudioPlayer = () => {
  // Get the current song and song data from the Redux store
  const songCurrent = useSelector((state) => state.songCurrent);
  const songData = useSelector((state) => state.songData);
  // Get the audioUrl from the songData array
  const audioUrl = songCurrent ? songData[songCurrent].songUrl : "";
  const artistName = songCurrent ? songData[songCurrent].screenName : "";
  const songName = songCurrent ? songData[songCurrent].songName : "";
  // State to store the WaveSurfer instance and the current volume
  const [wavesurfer, setWaveSurfer] = useState(null);

  function timeCalculator(value) {
    minute = Math.floor(value / 60);
    second = Math.floor(value - minute * 60);

    if (second < 10) {
      second = "0" + second;
    }

    return minute + ":" + second;
  }

  useEffect(() => {
    if (!audioUrl) return;

    // Destroy the Wavesurfer instance if it already exists
    if (wavesurfer) {
      wavesurfer.destroy();
    }
    // Import Wavesurfer
    import("wavesurfer.js").then((WaveSurfer) => {
      // Initialize Wavesurfer
      const wavesurfer = WaveSurfer.default.create({
        container: "#wave",
        waveColor: "#261b1b",
        progressColor: "#f44336",
        height: 40,
        length: 1000,
        scrollParent: false,
        hideScrollbar: true,
        skipLength: 30,
        cursorWidth: 0,
        barWidth: 3,
        barHeight: 1,
        barGap: 1,
      });

      // Load audio file
      wavesurfer.load(audioUrl);

      console.log("Audio URL:", audioUrl); // Log the audio URL

      // Store the Wavesurfer instance in state
      setWaveSurfer(wavesurfer);

      wavesurfer.on("ready", function () {
        // Initialize DOM elements
        /* const duration = document.querySelector("#duration");
        const current = document.querySelector("#current"); */
        const playPause = document.querySelector("#playPause");
        const skipBack = document.querySelector("#skipBack");
        const skipForward = document.querySelector("#skipForward");
        const volumeOn = document.querySelector("#volumeon");
        const volumeSlider = document.querySelector("#volumeSlider");

        wavesurfer.on("ready", function () {
          wavesurfer.play();
        });

        //change play button to pause on playing
        wavesurfer.on("play", function (e) {
          if (playPause) {
            playPause.classList.remove("fa-play");
            playPause.classList.add("fa-pause");
          }
        });

        //change pause button to play on pause
        wavesurfer.on("pause", function (e) {
          if (playPause) {
            playPause.classList.add("fa-play");
            playPause.classList.remove("fa-pause");
          }
        });

        if (playPause) {
          playPause.addEventListener("click", function (e) {
            wavesurfer.playPause();
          });
        }

        if (skipBack) {
          skipBack.addEventListener("click", function (e) {
            wavesurfer.skipBackward();
          });
        }

        if (skipForward) {
          skipForward.addEventListener("click", function (e) {
            wavesurfer.skipForward();
          });
        }

        //Add volumeOn button
        if (volumeOn) {
          volumeOn.addEventListener("click", function (e) {
            wavesurfer.setMute(!wavesurfer.getMute());
          });
        }

        //Add volumeSlider
        if (volumeSlider) {
          volumeSlider.addEventListener("input", function (e) {
            wavesurfer.setVolume(e.target.value / 100);
          });
        }
      });
    });
  }, [audioUrl]);

  return (
    <div className={styles.audioContainer}>
      <div className={styles.innerContainer}>
        <div className={styles.controlContainer}>
          <div className={styles.controls}>
            <div className={styles.buttons}>
              <i className="fa-solid fa-backward-step fa-2x" id="skipBack"></i>
              <i className="fa-solid fa-play fa-2x" id="playPause"></i>
              <i
                className="fa-solid fa-forward-step fa-2x"
                id="skipForward"
              ></i>
            </div>
          </div>
          <div className={styles.volume}>
            <input
              id="volumeSlider"
              className="volume-slider"
              type="range"
              name="volume-slider"
              min="0"
              max="100"
              defaultValue="75"
            ></input>
          </div>
        </div>
        <div className={styles.songInfo}>
          <div className={styles.artistName}>{artistName}</div>
          <div className={styles.songName}>{songName}</div>
        </div>
        <div className={styles.waveContainer}>
          <div id="wave"></div>
        </div>
      </div>
    </div>
  );
};

export default AudioPlayer;

Most of the javascipt is pretty standard implementation.

Any of you had this error before or can advise on this error please.

The audioUrl is fed to the component via redux.

Thanks in advance.

Yan
  • 161
  • 1
  • 13

1 Answers1

0

Wavesurfer uses WEB Apis that are not accessible during the server render.

When using some libraries with NextJS, you may run into this issue, since NextJS pre-renders the page on the server. On the server, there is no window object, no WebAudio API and many other things.

By placing these browser-only libraries in the useEffect they are ran after the component mounts on the client (browser).

useEffect hook is not ran on the server.

Jan Karnik
  • 175
  • 1
  • 7
  • Thanks Jan for this information. So you think by adding SSR: False to wavesurfer this will force it all client side and stop this error? – Yan Feb 08 '23 at 18:54
  • Could be, definitely worth the try. I'm not too familiar with wavesurfer unfortunately, but try checking out [this querstion](https://stackoverflow.com/questions/67217396/typeerror-cannot-read-property-ispaused-of-null) if you haven't already. – Jan Karnik Feb 08 '23 at 21:38
  • Thanks for your help Jan! I checked that similar post before posting and it didn't provide me with a solution unfortunately. I will let you know how i get on with the SSR angle. – Yan Feb 08 '23 at 22:04