Tuesday, 12 September 2023

Play button in custom React AudioPlayer requires two taps for initial play

I have a simple audio player (React/Vite) that automatically or manually moves on to the next track. It works as desired except for the initial press of the play button. The player opens with the pause button displayed. To start the player, the pause button has to be pressed (changes to play) and then the play button pressed to begin the audio and to use its feature. By all appearances, the code is written to display the play button on initial load. I can't see where the pause button is coming from on page load. Spent two afternoons on it now...a little help would be greatly appreciated.

The URL to the project: https://github.com/donpayne199/audio.git

Relevent code

  const AwesomeDrummers = (props) => {
  return (
    <section>
      <div>
        <h2 className="section-title">Awesome Drummers</h2>
        <AudioPlayer stories={props} />
      </div>
    </section>
  );
};


  const AudioPlayer = ({ stories }) => {
  const [textIndex, settextIndex] = useState(0);
  const [isPlaying, setIsPlaying] = useState(false);

  const { text, audioSrc } = stories.stories[textIndex];

  const audioRef = useRef(new Audio(audioSrc));
  const intervalRef = useRef();
  const isReady = useRef(false);

  const startTimer = () => {
    // Clear any running timers
    clearInterval(intervalRef.current);

    intervalRef.current = setInterval(() => {
      if (audioRef.current.ended) {
        toNexttext();
      }
    }, [1000]);
  };

  const toPrevtext = () => {
    if (textIndex - 1 < 0) {
      settextIndex(stories.stories.length - 1);
    } else {
      settextIndex(textIndex - 1);
    }
  };

  const toNexttext = () => {
    if (textIndex < stories.stories.length - 1) {
      settextIndex(textIndex + 1);
    } else {
      settextIndex(0);
    }
  };

  useEffect(() => {
    if (isPlaying) {
      audioRef.current.play();
      startTimer();
    } else {
      audioRef.current.pause();
    }
  }, [isPlaying]);

  // Cleanup when story changes
  useEffect(() => {
    audioRef.current.pause();

    audioRef.current = new Audio(audioSrc);

    if (isReady.current) {
      audioRef.current.play();
      setIsPlaying(true);
      startTimer();
    } else {
      // true = next pass
      isReady.current = true;
    }
  }, [textIndex]);

  useEffect(() => {
    // Pause and clean up on unmount
    return () => {
      audioRef.current.pause();
      clearInterval(intervalRef.current);
    };
  }, []);

  return (
    <>
      <div className="center-container">
        <div className="text-container">
          <p className="text-areas">{text}</p>
        </div>
      </div>
      <div>
        <AudioControls isPlaying={isPlaying} onPrevClick={toPrevtext} onNextClick={toNexttext} onPlayPauseClick={setIsPlaying} />
      </div>
    </>
  );
};


 const AudioControls = ({ isPlaying, onPlayPauseClick, onPrevClick, onNextClick }) => {
  return (
    <div className="audio-controls">
      <button type="button" className="prev" onClick={onPrevClick} aria-label="Previous">
        <BsChevronLeft />
      </button>
      {isPlaying ? (
        <button type="button" className="pause" onClick={() => onPlayPauseClick(false)} aria-label="Pause">
          <FaPause />
        </button>
      ) : (
        <button type="button" className="play" onClick={() => onPlayPauseClick(true)} aria-label="Play">
          <FaPlay />
        </button>
      )}

      <button type="button" className="next" onClick={onNextClick} aria-label="Next">
        <BsChevronRight />
      </button>
    </div>
  );
};


from Play button in custom React AudioPlayer requires two taps for initial play

No comments:

Post a Comment