Ответ 1
Redux - все о состоянии и последовательности.
Ваша цель - синхронизировать время песни и индикатор выполнения.
Я вижу два возможных аспекта:
1. Храните все в магазине.
Таким образом, вы должны сохранить текущее время песни (например, в секундах) в Магазине, потому что есть несколько зависимых компонентов и его трудно синхронизировать с ними без Store.
У вас мало событий, которые меняют текущее время:
- Текущее время. Например, каждые 1 секунду.
- Перемотка.
- Поиск времени.
При изменении времени вы отправите действие и обновите Store с новым временем. Таким образом, сохранение текущего времени песни все компоненты будут синхронизированы.
Управление состоянием в однонаправленном потоке данных с помощью операций диспетчеризации, редукторов и хранилищ - это метод 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 через refs в методе жизненного цикла componentDidMount.
Аудиотекст HTML5 содержит события DOM, и вы можете синхронизировать оба компонента, не касаясь магазина. Если в магазине нужно что-то сохранить, вы можете сделать это в любое время.
Пожалуйста, посмотрите исходный код реакции-аудио-проигрывателя и проверьте, как он обрабатывает ссылки и какой API предоставляет плагин. Конечно, вы можете вдохновить оттуда. Также вы можете повторно использовать его для своего использования.
Вот некоторые из методов API, которые связаны с вашими вопросами:
- onSeeked - вызов, когда пользователь перетаскивает индикатор времени в новое время. Передано событие.
- onPlay - Вызывается, когда пользователь играет краны. Передано событие.
- onPause - Вызывается, когда пользователь приостанавливает воспроизведение. Передано событие.
- onListen - Вызывается каждый раз прослушивание миллисекунд во время воспроизведения. Передано событие.
Какой подход следует использовать?
Это зависит от особенностей вашего использования. Однако, как правило, в обоих аспектах рекомендуется создать презентационный компонент с необходимыми методами API, и вам решать, сколько данных для управления в магазине.
Итак, я создал исходный компонент, чтобы вы могли проиллюстрировать, как обрабатывать ссылки на аудио и слайдер. Включение/выключение/поиск функций. Конечно, у этого есть недостатки, но, как я уже упоминал, это хорошая отправная точка.
Вы можете превратить его в презентационный компонент с хорошими 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 contents will be replaced with your component. -->
</div>