在 reactjs 中使用 HTMLAudioElement 创建简单的播放器

create simple player with HTMLAudioElement in reactjs

我正在创建一个简单播放器的网络应用程序。 我想获取正在播放的音乐的当前时间。
这是登录 useEffect 很棒。

React.useEffect(() => {
    Audio.addEventListener("timeupdate", (e) => {
      //setCurrentTime(e.target.currentTime);
      console.log(e.target.currentTime);
    });
    return () => {
      Audio.removeEventListener("timeupdate", () => {});
    };
  }, []);

问题
state 中设置 e.target.currentTime 时。音乐播放停止。

  React.useEffect(() => {
    Audio.addEventListener("timeupdate", (e) => {
      setCurrentTime(e.target.currentTime);
      console.log(e.target.currentTime);
    });
    return () => {
      Audio.removeEventListener("timeupdate", () => {});
    };
  }, []);


它将与本地 Audio 元素一起工作:

  import React from "react";
  import Musics from "../data/Musics";
  import Next from "../assets/next.svg";
  import Prev from "../assets/prev.svg";
  import Play from "../assets/play.svg";
  import Pause from "../assets/pause.svg";
  import Progress from "../components/Progress";
  import MusicTitle from "../components/MusicTitle";
  import Button from "../components/Button";
  import Container from "../components/Container";
  //import Audio from "../models/Audio";

  const MusicPlayer = () => {
    const [state, setState] = React.useState({
      isPlaying: false,
      title: Musics[0].name,

      path: Musics[0].path
      /**
       * Define your state here
       */
    });

    const [currentTime, setCurrentTime] = React.useState(0);

    const audio = new Audio();
    audio.src = state.path;
    audio.addEventListener("timeupdate", function () {
      let time = this.currentTime;
      setCurrentTime(time);
      console.log(time);
    });

    const next = () => {
      // TODO Implement this function
    };
    const prev = () => {
      // TODO Implement this function
    };
    const play = () => {
      console.log(5);
      audio.play();
    };

    return (
      <Container>
        <MusicTitle title={state.title} />
        <Progress currentTime={currentTime} />
        <div className="row justify-content-center">
          <Button data-testid="prev-btn" onClick={prev} src={Prev} />
          <Button
            data-testid={state.isPlaying ? "pause" : "play-btn"}
            onClick={play}
            src={state.isPlaying ? Pause : Play}
          />
          <Button data-testid="next-btn" onClick={next} src={Next} />
        </div>
      </Container>
    );
  };

  export default MusicPlayer;

编辑:回答 OP 为什么它在初始变体中不起作用

应用程序包含外部元素,不受 React 控制,因此应手动保持同步。这里,当调用 setCurrentTime 时,组件被重新评估,因此应防止重新分配 Audio.src 以不重置音频。此外,事件侦听器应该正确移除以防止内存泄漏。 (事实上​​ ,虽然带有本地 Audio 元素的代码正在运行,但它并不完美,并且在播放期间按下 play 将创建新的 Audio 元素并将同时播放)。以下是具有全局 Audio 元素的工作变体的更改。

import React from "react";
import Musics from "../data/Musics";
import Next from "../assets/next.svg";
import Prev from "../assets/prev.svg";
import Play from "../assets/play.svg";
import Pause from "../assets/pause.svg";
import Progress from "../components/Progress";
import MusicTitle from "../components/MusicTitle";
import Button from "../components/Button";
import Container from "../components/Container";
import Audio from "../models/Audio";

const MusicPlayer = () => {
  const [state, setState] = React.useState({
    isPlaying: false,
    title: Musics[0].name,

    path: Musics[0].path
    /**
     * Define your state here
     */
  });

  const [currentTime, setCurrentTime] = React.useState(0);

  React.useEffect(() => {
    const timeupdate = (e) => {
      setCurrentTime(e.target.currentTime);
      console.log(e.target.currentTime);
    };
    Audio.addEventListener("timeupdate", timeupdate);
    return () => {
      Audio.removeEventListener("timeupdate", timeupdate);
    };
  });

  if (!Audio.src)
    Audio.src = state.path;

  const next = () => {
    // TODO Implement this function
  };
  const prev = () => {
    // TODO Implement this function
  };
  const play = () => {
    console.log(5);
    Audio.play();
  };

  return (
    <Container>
      <MusicTitle title={state.title} />
      <Progress currentTime={currentTime} />

      <div className="row justify-content-center">
        <Button data-testid="prev-btn" onClick={prev} src={Prev} />
        <Button
          data-testid={state.isPlaying ? "pause" : "play-btn"}
          onClick={play}
          src={state.isPlaying ? Pause : Play}
        />
        <Button data-testid="next-btn" onClick={next} src={Next} />
      </div>
    </Container>
  );
};

export default MusicPlayer;