Как обрабатывать воспроизведение звука в React & Redux

Я делаю аудиоплеер. Он имеет паузу, перемотку назад и функции поиска времени. Как и кто должен обрабатывать аудиоэлемент?

  • Я могу отложить его в сторону магазин. Я не могу поставить его прямо на государство, так как он может быть клонирован. Тогда, когда в редукторе я могу взаимодействовать с ним. Проблема в том, что если мне нужно синхронизировать слайдер времени со звуком, мне нужно будет постоянно опрашивать магазин с помощью действия. Это также не имеет смысла семантически разговор.
  • Я могу создать пользовательский компонент React, Audio, который делает все, что я сказал. проблема не решена. Как обновить слайдер? Я мог бы опросить, но мне действительно не нравится это решение. Кроме того, если я не создам компонент, содержащий аудио и слайдер, мне все равно нужно будет использовать redux для подключения обоих.

Итак, каков наиболее редукс способ обработки звука с дисплеем прогресса?

1 ответов


Redux - это все о состоянии и последовательности.

ваша цель состоит в том, чтобы синхронизировать время песни и индикатор выполнения.

Я вижу два возможных приближения:

1. Держать все в магазине.

таким образом, вы должны сохранить текущее время песни (в секундах, например) в магазине, потому что есть несколько зависимых компонентов и его трудно синхронизировать их без магазина.

У вас есть несколько событий, которые изменяют текущий время:

  • само текущее время. Например, на каждую 1 секунду.
  • "назад".
  • времени искать.

при изменении времени вы отправите действие и обновите магазин с новым временем. Таким образом, сохраняя время текущей песни, все компоненты будут синхронизированы.

управление состоянием в однонаправленном потоке данных с диспетчеризацией действий, редукторами и хранилищами является способом Redux реализации любого деталь.

вот псевдо-код # 1 aproach:

class AudioPlayer extends React.Component {

    onPlay(second) {
        // Store song current time in the Store on each one second
        store.dispatch({ type: 'SET_CURRENT_SECOND', second });
    }

    onRewind(seconds) {
        // Rewind song current time
        store.dispatch({ type: 'REWIND_CURRENT_SECOND', seconds });
    }   

    onSeek(seconds) {
        // Seek song current time
        store.dispatch({ type: 'SEEK_CURRENT_SECOND', seconds });
    }

    render() {
        const { currentTime, songLength } = this.state;

        return <div>
            <audio onPlay={this.onPlay} onRewind={this.onRewind} onSeek={this.onSeek} />

            <AudioProgressBar currentTime songLength />
        </div>
    }
}

2. Держите как можно меньше в магазине.

если вышеуказанный aproach не соответствует вашим потребностям, например, у вас может быть много аудиоплееров на одном экране - может быть разрыв в производительности.

в этом случае вы можете получить доступ к тегу и компонентам HTML5 audio через refs в методе жизненного цикла componentDidMount.

аудио тег HTML5 имеет события DOM, и вы можете синхронизировать оба компонента, не касаясь магазина. Если есть необходимость сохранить что-то в магазине - вы можете сделать это в любое время.

пожалуйста, взгляните на react-исходный код аудиоплеера и проверьте, как он обрабатывает ссылки и какой API предоставляет плагин. Конечно, вы можете взять вдохновение оттуда. Также вы можете использовать его для вашего случая.

вот некоторые из методов API, которые связаны с вашим вопросы:

  • onSeeked-вызывается, когда пользователь перетаскивает индикатор времени в Новое время. Прошло мероприятие.
  • onPlay-вызывается, когда пользователь нажимает play. Прошло мероприятие.
  • onPause-вызывается, когда пользователь приостанавливает воспроизведение. Прошло мероприятие.
  • onListen-вызывается каждый listenInterval миллисекунд во время воспроизведения. Прошло мероприятие.

какой подход я должен использовать?

Это зависит от вашей особенности прецедентов. Однако, вообще говоря, в обоих aproaches это хорошая идея реализовать презентационная составляющая с необходимыми методами API, и это до вас, чтобы решить, сколько данных для управления в магазине.

поэтому я создал начальный компонент для вас, чтобы проиллюстрировать, как обрабатывать ссылки на аудио и слайдер. Start / Stop / Поиск функций включены. Конечно, у него есть недостатки, но, как я уже упоминал, это хорошее начало точка.

вы можете развить его в презентационный компонент с хорошими методами API, который соответствует вашим потребностям.

class Audio extends React.Component {
	constructor(props) {
		super(props);
		
		this.state = {
			duration: null
		}
  	};
	
	handlePlay() {
		this.audio.play();
	}
	
	handleStop() {
		this.audio.currentTime = 0;
		this.slider.value = 0;
		this.audio.pause(); 
	}

	componentDidMount() {
		this.slider.value = 0;
		this.currentTimeInterval = null;
		
		// Get duration of the song and set it as max slider value
		this.audio.onloadedmetadata = function() {
			this.setState({duration: this.audio.duration});
		}.bind(this);
		
		// Sync slider position with song current time
		this.audio.onplay = () => {
			this.currentTimeInterval = setInterval( () => {
				this.slider.value = this.audio.currentTime;
			}, 500);
		};
		
		this.audio.onpause = () => {
			clearInterval(this.currentTimeInterval);
		};
		
		// Seek functionality
		this.slider.onchange = (e) => {
			clearInterval(this.currentTimeInterval);
			this.audio.currentTime = e.target.value;
		};
	}

	render() {
		const src = "https://files.freemusicarchive.org/music%2Fno_curator%2FThe_Womb%2FBang_-_An_Introduction_to_The_Womb%2FThe_Womb_-_02_-_Sex_Club.mp3";
		
		
		return <div>
			<audio ref={(audio) => { this.audio = audio }} src={src} />
			
			<input type="button" value="Play"
				onClick={ this.handlePlay.bind(this) } />
			
			<input type="button"
					value="Stop"
					onClick={ this.handleStop.bind(this) } />
			
			<p><input ref={(slider) => { this.slider = slider }}
					type="range"
					name="points"
					min="0" max={this.state.duration} /> </p>
		</div>
	}
}

ReactDOM.render(<Audio />, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

Если у вас есть какие-либо вопросы, не стесняйтесь комментировать ниже! :)