programing

React.js에서의 사운드 재생

newstyles 2023. 3. 25. 10:56

React.js에서의 사운드 재생

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

리액트 앱에서 url(this.url)로 사운드를 재생하기 위해 사용하는 코드입니다.재생 버튼을 누르면 오류가 발생합니다.

Uncaughed TypeError: 정의되지 않은 속성 '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;

후크 버전(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;

업데이트 20년 3월 16일: 여러 플레이어 동시 실행

@Cold_Class의 코멘트에 대한 응답:

유감스럽게도 이러한 컴포넌트를 여러 개 사용해도 다른 컴포넌트의 음악이 재생을 시작할 때마다 재생이 중지되지 않습니다.이 문제에 대한 간단한 해결책을 제안해 주시겠습니까?

코드베이스의 .Player a a a a to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to로 올려야 하기 때문입니다.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

»App.jsMultiPlayer★★★★★★★★★★★★★★★★★★:

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컴포넌트에 ; 모모컴컴컴컴 ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;.urls URL)입니다.
  • 각 플레이어의 상태를 추적하는 배열

toggle을 다음합니다.

  • 현재 활성 상태인 플레이어가 있고(즉, 오디오가 재생 중) 이 활성 플레이어가 토글 메서드의 대상이 아닌 경우 해당 플레이어의 재생 상태를 false로 되돌리고 대상 플레이어의 재생 상태를 true로 설정합니다. [다른 오디오 스트림이 이미 재생 중일 '재생'을 클릭했습니다]
  • 현재 활성 상태인 플레이어가 전환 방식의 대상 플레이어인 경우 대상 플레이어의 플레이 상태를 false로 되돌리기만 하면 됩니다. ['클릭'을 클릭했습니다.
  • 현재 활성화된 플레이어가 없는 경우 대상 플레이어의 상태를 true로 설정하십시오(현재 재생 중인 오디오 스트림이 없을 때 '재생'을 클릭했습니다).

에 주의:toggle소스 플레이어의 인덱스(즉, 해당 버튼이 클릭된 하위 구성요소의 인덱스)를 받아들이도록 메서드가 큐레이션됩니다.

는 '오디오 오브젝트 제어로 .useEffect원래 후크에서는 그렇지만 업데이트 할 때마다 오디오 오브젝트 전체를 반복해야 하기 때문에 조금 더 복잡합니다.

에 대한 는 두 'ended' 됩니다.useEffect원래 후크에서와 같으나 이러한 단일 객체가 아닌 오디오 객체의 배열을 처리하도록 업데이트되었습니다.

됩니다.MultiPlayer컴포넌트플레이어를 는, 의 플레이어에 맵 .Player 및 를 사용합니다 (a) "URL"은 플레이어의 현재 상태와 소스 스트리밍 URL을 포함합니다.

Code Sandbox 데모

할 요, 아, 아, 아, 아, 아.useSound

이를 수행하려면 먼저 npm 패키지를 설치합니다.

npm install use-sound

Import:

import useSound from 'use-sound'
import mySound from '../assets/sounds/yourSound.mp3' // Your sound file path here

사용 예 1

심플한 어프로치..

function MyButton(){
  const [playSound] = useSound(mySound)
  
  return (
    <button onClick={() => playSound()}>
       Play Sound
    </button>
  )
}

사용 예 2

이 설정에서는 볼륨을 제어할 수 있습니다.ㅇㅇㅇㅇ.playSound()라고 합니다.handleClick()클릭만으로 소리를 재생하는 것보다 더 많은 작업을 수행할 수 있습니다.

function MyButton(){
  const [playSound] = useSound(mySound, { volume: 0.7 }) // 70% of the original volume
  
  const handleClick = () => {
    playSound()
    // maybe you want to add other things here?
  }

  return (
    <button onClick={() => handleClick()}>
       Play Sound
    </button>
  )
}

자세한 내용은 여기를 클릭해 주세요.

나는 이 답변의 구현에 대해 다른 문제에 직면했다.

브라우저는 리렌더 할 때마다 계속 소리를 다운로드하려고 하는 것 같습니다.

나는 결국 그것을 이용하게 되었다.useMemo의존관계가 없는 Audio의 경우 후크가 Audio를 한 번만 생성하고 재생성하지 않도록 합니다.

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

const useAudio = url => {
    const audio = useMemo(() => 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];
};

export default useAudio;

오디오가 HTMlement 태그이기 때문에 Next Js로 작업할 때 몇 가지 문제가 있었습니다.결국, 큰 에러를 일으키고 있었기 때문에, 저는 더 공부하기로 결정했고, 그 결과는 다음과 같습니다.

  //inside your component function.
  const [audio] = useState( typeof Audio !== "undefined" && new Audio("your-url.mp3")); //this will prevent rendering errors on NextJS since NodeJs doesn't recognise HTML tags neither its libs.
  const [isPlaying, setIsPlaying] = useState(false);

플레이어를 처리하기 위해 useEffect를 만들었습니다.

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

지금까지 만든 기능에 따라 "isPlaying" 상태를 관리합니다.

Uncaughed TypeError: 정의되지 않은 속성 'setState'를 읽을 수 없습니다.

이 에러는, 이 키워드가 JavaScript 로 동작하기 때문에 발생합니다.이 문제를 해결하면 오디오가 제대로 재생될 것 같습니다.

에 ㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇ.console.log(this)에 inside inside inside play()곧 알게 될 것이다this정의되어 있지 않기 때문에 에러가 발생합니다.this.setState().기본적으로 가치this안에서.play()그 기능이 어떻게 호출되느냐에 따라 달라집니다.

React에는 다음 두 가지 일반적인 솔루션이 있습니다.

  1. bind()를 사용하여 호출 방법에 관계없이 함수의 값을 설정합니다.
constructor(props) {
  super(props);
  this.play() = this.play.bind(this);
}
  1. 자체 바인딩을 제공하지 않는 화살표 기능 사용
<button onClick={() => {this.play()}}>Play</button>

이제 다음 항목에 액세스할 수 있습니다.this.setState그리고.this.audio안에서.play()에 대해서도 마찬가지입니다.pause().

나는 여기 파티에 조금 늦었지만 '토마스 헤네스'는 뒷걸음질쳤다.

이것을 보는 사람들이 직면하게 될 한 가지 문제는, 만약 당신이 이 코드를 여러 페이지가 있는 앱에서 말 그대로 사용하려고 한다면, 그들은 즐거운 시간을 보내지 못할 것이라는 것이다.상태는 컴포넌트에서 관리되므로 재생, 탐색 및 재생이 가능합니다.

컴포넌트의 상태를 App.js에 푸시하고 관리하려면 컴포넌트의 상태를 App.js로 변경합니다.

내가 무슨 말을 하는지 보여줄게.

플레이어의 컴포넌트는 다음과 같습니다.

import React, { Component } from 'react'

class MusicPlayer extends Component {
  render() {
    const { playing } = this.props.player;

    return (
      <div>
        <button onClick={this.props.toggleMusic.bind(this, playing)}>{playing ? "Pause" : "Play"}</button>
      </div>
    );
  }
};

export default MusicPlayer;

그런 다음 App.js에서는 다음과 같이 표시됩니다(TODO 목록 샘플 앱 사용).

import React, { Component } from 'react';
import { BrowserRouter as Router, Route  } from 'react-router-dom'
import './App.css';
import Header from './componets/layout/Header'
import Todos from './componets/Todos'
import AddTodo from './componets/AddTodo'
import About from './componets/pages/About'
import MusicPlayer from './componets/MusicPlayer'
import axios from 'axios';


class App extends Component {
  constructor(props) {
    super(props);
    this.state = { playing: false, todos: [] }
    this.audio = new Audio('<YOUR MP3 LINK HERE>');
  }

  componentDidMount(){
    axios.get('https://jsonplaceholder.typicode.com/todos')
      .then(res => this.setState({ playing: this.state.playing, todos: res.data }))
  }

  toggleComplete = (id) => {
    this.setState({ playing: this.state.playing, todos: this.state.todos.map(todo => {
      if (todo.id === id){
        todo.completed = !todo.completed
      }
      return todo
    }) });
  }

  delTodo = (id) => {
    axios.delete(`https://jsonplaceholder.typicode.com/todos/${id}`)
      .then(res => this.setState({ playing: this.state.playing, todos: [...this.state.todos.filter(todo => todo.id !== id)] }));
  }

  addTodo = (title) => {
    axios.post('https://jsonplaceholder.typicode.com/todos', {
      title,
      completed: false
    })
      .then(res => this.setState({ playing: this.state.playing, todos: [...this.state.todos, res.data]}))

  }

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

  render() {
    return (
      <Router>
        <div className="App">
          <div className="container">
            <Header />
            <Route exact path="/" render={props => (
              <React.Fragment>
                <AddTodo addTodo={this.addTodo} />
                <Todos todos={this.state.todos} toggleComplete={this.toggleComplete} delTodo={this.delTodo} />
              </React.Fragment>
            )} />
            <Route path="/About" render={props => (
              <React.Fragment>
                <About />
                <MusicPlayer player={this.state} toggleMusic={this.toggleMusic} />
              </React.Fragment>
            )} />
          </div>
        </div>
      </Router>
    );
  }
}

export default App;

이거 한번 해봐, 나한테는 잘 돼

var tinung = `${window.location.origin}/terimakasih.ogg`;
                        var audio = document.createElement("audio");

                        audio.autoplay = true;
                        audio.load();
                        audio.addEventListener(
                            "load",
                            function() {
                                audio.play();
                            },
                            true
                        );
                        audio.src = tinung;

언급URL : https://stackoverflow.com/questions/47686345/playing-sound-in-react-js