.play() does not works as expected on a React Component

Viewed 101

I'm building a audio Player, but when i try to play a audio tag it not works as expected. I'm using useEfect() and useRef() calling .play() or .pause() to play a .mp3, but this methods always returns a Promise that is always as pending status and not execute the .then() or .catch(). Does anyone knows how to solve this problem?

My component's code:

import React, { useState, useEffect, useRef } from 'react';
import Details from '../Details';
import Controls from '../Controls';

function Player(props) {
  const audioEl = useRef(null);

  const [isPlaying, setIsPlaying] = useState(false);

  useEffect(() => {
    if (isPlaying) {
      let promisseTemp = audioEl.current.play();
      if (promisseTemp !== undefined)
        promisseTemp
          .then((_) => {
            console.log('OK');
          })
          .catch((erro) => console.log(erro));
    } else {
      let promisseTemp = audioEl.current.pause();
      if (promisseTemp !== undefined)
        promisseTemp
          .then((_) => {
            console.log('OK');
          })
          .catch((erro) => console.log(erro));
    }
  });

  const skipEpisode = (forwards = true) => {
    if (forwards) {
      props.setCurrentEpisodeIndex(() => {
        let temp = props.currentEpisodeIndex;
        temp++;

        if (temp > props.episodes.length - 1) return 0;
        return temp;
      });
    } else {
      props.setCurrentEpisodeIndex(() => {
        let temp = props.currentEpisodeIndex;
        temp--;

        if (temp < 0) return props.episodes.length - 1;
        return temp;
      });
    }
  };

  return (
    <div className="Player">
      <audio scr={window.location.origin + props.episodes[props.currentEpisodeIndex].scr} ref={audioEl}></audio>
      <h4>Playing now</h4>
      <Details episode={props.episodes[props.currentEpisodeIndex]} />
      <Controls isPlaying={isPlaying} setIsPlaying={setIsPlaying} skipEpisode={skipEpisode} />
    </div>
  );
}

export default Player;
1 Answers

your useEffect should look like this:

useEffect(() => {
    if (audioEl.current) {
        if (isPlaying) {
            audioEl.current.play()
                .then((_) => {
                    console.log("OK");
                })
                .catch((erro) => console.log(erro));
        } else {
            audioEl.current.pause()
                .then((_) => {
                    console.log("OK");
                })
                .catch((erro) => console.log(erro));
        }
    }
}, [isPlaying]);

You are missing the second argument in useEffect, in the current state it would be called for every render. You want to add the array of dependencies as a second argument. In your case [isPlaying] so it is called every time isPlaying changes.

You should probably make sure audioEl.current is defined also before calling methods on it.

Related