admin管理员组文章数量:1399815
I have a React ponent that plays/pauses audio when you click on a button. It works great and I render about 5 of these on a page at once. However, if you click play on one, and then click play on another, both audio's are playing, which isn't great. Here's my code for the ponent:
import React from 'react';
import playIcon from './images/play.png';
import pauseIcon from './images/pause.png';
class Music extends React.Component {
constructor(props) {
super(props);
this.state = { 'play': false };
this.url = props.src;
this.audio = new Audio(this.url);
this.audio.preload = 'none';
this.togglePlay = this.togglePlay.bind(this);
}
togglePlay() {
this.setState({'play': !this.state.play}, () => {
this.state.play ? this.audio.play() : this.audio.pause();
});
}
ponentWillUnmount () {
this.audio.pause();
}
render() {
return (
<div style={this.props.style} className={this.props.className}>
{this.state.play
? <button className="audio-button" aria-label="Pause" onClick={this.togglePlay}><img src={pauseIcon} width="34" height="34" alt="Pause"></img></button>
: <button className="audio-button" aria-label="Play" onClick={this.togglePlay}><img src={playIcon} width="34" height="34" alt="Play"></img></button>}
</div>
);
}
}
export default Music;
I've done some looking around and a potential solution is to use redux or some other state management library. I'd like to avoid this as I otherwise have no need for that in this site. I've looked into event listeners (namely the solution proposed here) but when I do a document.getElementsByTagName('audio')
I get back an empty HTMLCollection
. This solution is closer, but I can't bridge the gap between it's implementation in jQuery to the one I'm using in React.
Is there a way to identify the playing audio and pause it from a React Component before playing new audio? Any and all suggestions are appreciated.
I have a React ponent that plays/pauses audio when you click on a button. It works great and I render about 5 of these on a page at once. However, if you click play on one, and then click play on another, both audio's are playing, which isn't great. Here's my code for the ponent:
import React from 'react';
import playIcon from './images/play.png';
import pauseIcon from './images/pause.png';
class Music extends React.Component {
constructor(props) {
super(props);
this.state = { 'play': false };
this.url = props.src;
this.audio = new Audio(this.url);
this.audio.preload = 'none';
this.togglePlay = this.togglePlay.bind(this);
}
togglePlay() {
this.setState({'play': !this.state.play}, () => {
this.state.play ? this.audio.play() : this.audio.pause();
});
}
ponentWillUnmount () {
this.audio.pause();
}
render() {
return (
<div style={this.props.style} className={this.props.className}>
{this.state.play
? <button className="audio-button" aria-label="Pause" onClick={this.togglePlay}><img src={pauseIcon} width="34" height="34" alt="Pause"></img></button>
: <button className="audio-button" aria-label="Play" onClick={this.togglePlay}><img src={playIcon} width="34" height="34" alt="Play"></img></button>}
</div>
);
}
}
export default Music;
I've done some looking around and a potential solution is to use redux or some other state management library. I'd like to avoid this as I otherwise have no need for that in this site. I've looked into event listeners (namely the solution proposed here) but when I do a document.getElementsByTagName('audio')
I get back an empty HTMLCollection
. This solution is closer, but I can't bridge the gap between it's implementation in jQuery to the one I'm using in React.
Is there a way to identify the playing audio and pause it from a React Component before playing new audio? Any and all suggestions are appreciated.
Share Improve this question edited Jun 1, 2018 at 16:41 quicklikerabbit asked May 30, 2018 at 1:00 quicklikerabbitquicklikerabbit 3,5566 gold badges29 silver badges41 bronze badges 1- 1 Why isn't the audio a ponent? – Maximilian Burszley Commented May 30, 2018 at 1:12
3 Answers
Reset to default 2import React from 'react';
import audio1 from './audio1.mp3';
import audio2 from './audio2.mp3';
class AudioList extends React.Component {
constructor (props) {
super(props);
this.audios = props.list.map(audio => new Audio(audio));
}
getCurrentAudio () {
return this.audios.find(audio => false === audio.paused);
}
toggle (nextAudio) {
const currentAudio = this.getCurrentAudio();
if (currentAudio && currentAudio !== nextAudio) {
currentAudio.pause();
}
nextAudio.paused ? nextAudio.play() : nextAudio.pause();
}
render () {
return (
<div>
{ this.audios.map((audio, index) =>
<button onClick={() => this.toggle(audio) }>
PLAY AUDIO { index }
</button>
) }
</div>
)
}
}
export default () => <AudioList list={[ audio1, audio2 ]} />;
PS: new Audio(url)
returns a HTMLAudioElement.
Got some big hints from Xuezheng Ma and TheIncorrigible1. Basically moved audio into it's own module. play
and pause
methods are exported from that, and currentlyPlaying
is tracked in that module.
I adjusted my Music
ponent to look like this
import React from 'react';
import playIcon from './images/play.png';
import pauseIcon from './images/pause.png';
import globalAudio from './globalAudio';
class Music extends React.Component {
constructor(props) {
super(props);
this.state = { 'play': false };
this.name = props.src;
this.togglePlay = this.togglePlay.bind(this);
}
togglePlay() {
this.setState({'play': !this.state.play}, () => {
this.state.play ? globalAudio.play(this.name) : globalAudio.pause(this.name);
});
}
ponentWillUnmount () {
globalAudio.pause(this.name);
}
render() {
return (
<div style={this.props.style} className={this.props.className}>
{this.state.play
? <button className="audio-button" aria-label="Pause" onClick={this.togglePlay}><img src={pauseIcon} width="34" height="34" alt="Pause"></img></button>
: <button className="audio-button" aria-label="Play" onClick={this.togglePlay}><img src={playIcon} width="34" height="34" alt="Play"></img></button>}
</div>
);
}
}
export default Music;
And my new module globalAudio
:
import audio1 from './audio1.mp3';
import audio2 from './audio2.mp3';
import audio3 from './audio3.mp3';
import audio4 from './audio4.mp3';
import audio5 from './audio5.mp3';
const audios = {
'audio1': new Audio(audio1),
'audio2': new Audio(audio2),
'audio3': new Audio(audio3),
'audio4': new Audio(audio4),
'audio5': new Audio(audio5)
};
let currentlyPlaying = null;
const play = (name) => {
if (currentlyPlaying) {
audios[currentlyPlaying].pause();
}
audios[name].play();
currentlyPlaying = name;
};
const pause = (name) => {
currentlyPlaying = null;
audios[name].pause();
};
export default {
pause,
play
};
Thanks for all of the suggestions, they were all very helpful.
Create a module to handle audio. Expose methods like play, pause, resume, etc, to Music
, and keep track of different audios from all five Music
instance you have. Whenever a new audio is played, paused the old one.
本文标签: javascriptManage Multiple Audio Sources in ReactStack Overflow
版权声明:本文标题:javascript - Manage Multiple Audio Sources in React - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744190955a2594515.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论