在 React.js 中播放声音

2023-12-01

import React, { Component } from 'react'
import { Button, Input, Icon,Dropdown,Card} from 'semantic-ui-react'
import { Link } from 'react-router-dom'
import $ from 'jquery'
import styles from './Home.scss'
import Modal from './Modal.jsx'
import MakeChannelModal from './MakeChannelModal.jsx'

class Music extends React.Component {
    constructor(props) {
    super(props);
    this.state = {

      play: false,
      pause: true

    };

    this.url = "http://streaming.tdiradio.com:8000/house.mp3";
    this.audio = new Audio(this.url);

  }

  play(){
    this.setState({
      play: true,
      pause: false
    });
    console.log(this.audio);
    this.audio.play();
  }
  
  pause(){
  this.setState({ play: false, pause: true });
    this.audio.pause();
  }
  
  render() {
    
  return (
    <div>
      <button onClick={this.play}>Play</button>
      <button onClick={this.pause}>Pause</button>
    </div>
    );
  }
}


export default Music

这是我用来在我的 React 应用程序中通过 url (this.url) 播放声音的代码。当我按下播放按钮时,出现错误

未捕获的类型错误:无法读取未定义的属性“setState”

我不确定为什么会发生这种情况,因为我没有看到任何未定义的状态。 A;;各州已宣布。

我是个新手,所以我可能会错过一些非常重要的东西。

请帮忙!


ES6 类属性语法

class Music extends React.Component {
  state = {
    play: false
  }
  audio = new Audio(this.props.url)

  componentDidMount() {
    audio.addEventListener('ended', () => this.setState({ play: false }));
  }
  
  componentWillUnmount() {
    audio.removeEventListener('ended', () => this.setState({ play: false }));  
  }

  togglePlay = () => {
    this.setState({ play: !this.state.play }, () => {
      this.state.play ? this.audio.play() : this.audio.pause();
    });
  }

  render() {
    return (
      <div>
        <button onClick={this.togglePlay}>{this.state.play ? 'Pause' : 'Play'}</button>
      </div>
    );
  }
}

export default Music;

Hooks 版本(React 16.8+):

import React, { useState, useEffect } from "react";

const useAudio = url => {
  const [audio] = useState(new Audio(url));
  const [playing, setPlaying] = useState(false);

  const toggle = () => setPlaying(!playing);

  useEffect(() => {
      playing ? audio.play() : audio.pause();
    },
    [playing]
  );

  useEffect(() => {
    audio.addEventListener('ended', () => setPlaying(false));
    return () => {
      audio.removeEventListener('ended', () => setPlaying(false));
    };
  }, []);

  return [playing, toggle];
};

const Player = ({ url }) => {
  const [playing, toggle] = useAudio(url);

  return (
    <div>
      <button onClick={toggle}>{playing ? "Pause" : "Play"}</button>
    </div>
  );
};

export default Player;

更新 03/16/2020:多个并发玩家

回应@Cold_Class的评论:

不幸的是,如果我使用多个这些组件,每当我开始播放另一个组件时,来自其他组件的音乐就不会停止播放 - 对于此问题的简单解决方案有什么建议吗?

不幸的是,没有直接的解决方案使用我们用来实现单个Player成分。原因是你必须以某种方式将单人游戏状态提升到MultiPlayer父组件以便toggle功能能够暂停与您直接交互的玩家以外的其他玩家。

一种解决方案是修改挂钩本身以同时管理多个音频源。这是一个示例实现:

import React, { useState, useEffect } from 'react'

const useMultiAudio = urls => {
  const [sources] = useState(
    urls.map(url => {
      return {
        url,
        audio: new Audio(url),
      }
    }),
  )

  const [players, setPlayers] = useState(
    urls.map(url => {
      return {
        url,
        playing: false,
      }
    }),
  )

  const toggle = targetIndex => () => {
    const newPlayers = [...players]
    const currentIndex = players.findIndex(p => p.playing === true)
    if (currentIndex !== -1 && currentIndex !== targetIndex) {
      newPlayers[currentIndex].playing = false
      newPlayers[targetIndex].playing = true
    } else if (currentIndex !== -1) {
      newPlayers[targetIndex].playing = false
    } else {
      newPlayers[targetIndex].playing = true
    }
    setPlayers(newPlayers)
  }

  useEffect(() => {
    sources.forEach((source, i) => {
      players[i].playing ? source.audio.play() : source.audio.pause()
    })
  }, [sources, players])

  useEffect(() => {
    sources.forEach((source, i) => {
      source.audio.addEventListener('ended', () => {
        const newPlayers = [...players]
        newPlayers[i].playing = false
        setPlayers(newPlayers)
      })
    })
    return () => {
      sources.forEach((source, i) => {
        source.audio.removeEventListener('ended', () => {
          const newPlayers = [...players]
          newPlayers[i].playing = false
          setPlayers(newPlayers)
        })
      })
    }
  }, [])

  return [players, toggle]
}

const MultiPlayer = ({ urls }) => {
  const [players, toggle] = useMultiAudio(urls)

  return (
    <div>
      {players.map((player, i) => (
        <Player key={i} player={player} toggle={toggle(i)} />
      ))}
    </div>
  )
}

const Player = ({ player, toggle }) => (
  <div>
    <p>Stream URL: {player.url}</p>
    <button onClick={toggle}>{player.playing ? 'Pause' : 'Play'}</button>
  </div>
)


export default MultiPlayer

Example App.js使用MultiPlayer成分:

import React from 'react'
import './App.css'
import MultiPlayer from './MultiPlayer'

function App() {
  return (
    <div className="App">
      <MultiPlayer
        urls={[
          'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3',
          'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3',
          'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-3.mp3',
        ]}
      />
    </div>
  )
}

export default App

这个想法是管理 2 个并行数组:

  • 您的音频源(由urls您传递给父组件的道具;这urlsprops 是一个字符串数组(您的 MP3 URL))
  • 跟踪每个玩家状态的数组

The toggle方法根据以下逻辑更新玩家状态数组:

  • 如果当前有一个玩家处于活动状态(即音频正在播放)并且该活动玩家不是切换方法的目标玩家,则将该玩家的播放状态恢复为 false,并将目标播放器的播放状态设置为 true [您单击了“播放” ' 尽管another音频流已经在播放]
  • 如果当前活动的玩家是切换方法的目标玩家,只需将目标玩家的播放状态恢复为 false [您单击了“暂停”]
  • 如果当前没有活动的播放器,只需将目标播放器的状态设置为 true [您在当前没有音频流正在播放时单击“播放”]

请注意,toggle方法被柯里化以接受源玩家的索引(即单击相应按钮的子组件的索引)。

实际的音频对象控制发生在useEffect与原始钩子一样,但稍微复杂一些,因为我们必须在每次更新时迭代整个音频对象数组。

类似地,音频流“结束”事件的事件侦听器会在一秒钟内处理useEffect与原始钩子一样,但更新为处理音频对象数组而不是单个此类对象。

最后,从父级调用新的钩子MultiPlayer组件(容纳多个玩家),然后映射到个人Player使用 (a) 一个包含播放器当前状态及其源流 URL 的对象,以及 (b) 使用播放器索引进行柯里化的切换方法。

代码沙盒演示

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 React.js 中播放声音 的相关文章

随机推荐

  • 使用 asyncio 时无法使用 os.fork() 将多个进程绑定到一个套接字服务器

    我们都知道 使用 asyncio 可以显着提高套接字服务器的性能 如果我们能够利用 cpu 中的所有核心 可能通过多处理模块或os fork etc 我现在正在尝试构建一个多核套接字服务器演示 其中一个异步套接字服务器侦听每个核心并全部绑定
  • 具有相同标识符值的不同对象已与保存时的会话错误相关联[重复]

    这个问题在这里已经有答案了 可能的重复 Spring Hibernate 具有相同标识符值的不同对象已与会话关联 我的休眠注释一直存在问题 我在两个类之间有双向关系 这是映射 感谢axtavt Entity public class Rec
  • PhantomJS:在 REPL 中运行时 page.open() 没有响应

    我试图通过标准输入发送一些 phantomJS 来运行它 但我打开的网页没有响应 这是我尝试执行的 JavaScript require webpage create open http google com function consol
  • 错误:无法读取 null 的属性“close”

    你好 亲爱的社区 我想知道为什么当我尝试使用 mongodb 和 nodejs 时会收到此错误 const MongoClient require mongodb MongoClient MongoClient connect mongod
  • usaco:十三号星期五我的逻辑有什么问题吗?

    该问题要求计算一周中每一天出现的 13 号的数量 这是我的代码 class CopyOffriday public static void main String args throws IOException BufferedReader
  • Spark 在运行 LinearRegressionwithSGD 时未利用所有核心

    我正在本地计算机 16G 8 个 cpu 核心 上运行 Spark 我试图在大小为 300MB 的数据集上训练线性回归模型 我检查了CPU统计信息以及正在运行的程序 它只执行一个线程 文档称他们已经实现了 SGD 的分布式版本 http s
  • 在带有子图的 geopandas 图中添加图例会改变图的大小

    我想用 matplotlib 子图绘制两个 GeoPandas 图 两张地图具有相同的图例 因此我只想有一个图例 但是 如果我向 GeoPandas 图之一添加图例 该图就会变得稍微小一些 这是一个问题 因为这两个图的大小会变得不同 这是我
  • HighlightBrushKey 设置在 Windows 7 中不起作用

    我在资源字典中定义了以下样式
  • 如何将数据组值分配给用 C# 创建的 html 元素?

    我有一个场景 我需要有条件地向上滑动 或隐藏 控件 元素集 我喜欢我找到的答案here来自 QBM5 关于将数据组分配给可以向上滑动的控件 请原谅我的语法 如下所示
  • Socket.IO版本输出

    我升级了套接字 io从 0 9 16 到 1 0 6 并用于输出如下版本 var io require socket io console log Socket IO Version io version 会给我 Socket IO Ver
  • 语法错误:在“<”之前缺少“,”

    很长一段时间后 我才开始用 c 编码 也许我在这里遗漏了一些语法上明显的东西 但我已经搜索了很长时间 但在任何地方都找不到对我的问题的引用 我正在尝试创建一个自定义 C 类set and multiset 这是我的班级cset h prag
  • Glassfish Web 部署后执行代码[重复]

    这个问题在这里已经有答案了 我正在尝试在 Glassfish 上运行 Java Web 服务 有一些初始化代码设置一些变量并从 Glassfish 环境本身检索一些信息 我在 WebService 类内的静态初始化程序中拥有该代码 但是该代
  • Qt QListWidgetItem 多行

    我有一个非常简单的QListWidget对象 我想构建一个文件夹列表 当我将一个项目添加到我的列表中时 我会执行以下操作 void LessCC on addFolderButton clicked QString dirName QFil
  • 在matlab中从邻接矩阵创建图

    我在 matlab 中有一个邻接矩阵 如何绘制它的图形 由于我有 gt 500 个节点 因此我无法将 gplot 与随机 或类似网格 坐标一起使用 所以假设你有生物信息学工具箱 the biograph功能非常适合您想做的事情 这是我过去所
  • SQLSRV 和存储过程中的多重选择

    我有一个存储过程 它创建一个临时表 test 用另一个表中的数据填充它 在此临时表上运行 3 个选择并删除它 原始表大小超过 20 GB 并且 3 个 SELECT 语句包含原始 SP 上的许多不同条件 我正在使用 SQLSRV 从 PHP
  • 如何扩展 Bitmap 类

    我正在尝试扩展 Bitmap 类 以便我可以将自己的效果应用于图像 当我使用这段代码时 namespace ImageEditor public class Effects System Drawing Bitmap public void
  • 检测已安装的 Outlook 并动态加载 INterop.Outlook

    我在 VS2010 中有一个 Windows 窗体应用程序 它引用了 Interop Outlook 2003 然后 我重新安装了Windows XP和VS2010 但没有安装Outlook 现在 该项目无法编译 我认为 如果 Outloo
  • 卸载后无法安装cocoa pods,导致错误

    我删除了可可豆荚 因为它声称已安装 但后来一直说找不到命令豆荚 当尝试重新安装 cocoapods 时 sudo gem install cocoa pods v 我收到此错误 错误 执行 gem 时 Errno EPERM 不允许操作 u
  • Kotlin 中带参数的单例

    我正在尝试将 Android 应用程序从 Java 转换为 Kotlin 应用程序中有一些单例 我为没有构造函数参数的单例使用了一个伴随对象 还有另一个带有构造函数参数的单例 Java代码 public class TasksLocalDa
  • 在 React.js 中播放声音

    import React Component from react import Button Input Icon Dropdown Card from semantic ui react import Link from react r