В настоящее время я создаю музыкальное приложение, и у меня есть вопрос о правильном подходе к аудиообъектам с точки зрения их хранения и их текущего состояния в React / Redux.
В настоящее время я отправляю действие в одном из моих компонентов, которое переходит к следующему редуктору, чтобы установить звуковой объект как часть состояния:
Reducer.js
import { fromJS } from 'immutable';
const initialState = fromJS({
audioTrack: false
});
export const musicPlayer = (state = initialState, action) => {
switch (action.type) {
case 'musicPlayer/PLAY_TRACK': {
const mergeObj = {};
const audioTrack = state.get('audioTrack');
mergeObj.audioTrack = audioTrack;
if (!audioTrack) {
mergeObj.audioTrack = new Audio('../../public/music/test.mp3');
mergeObj.audioTrack.play();
} else if (state.get('audioTrack').paused) {
mergeObj.audioTrack.play();
} else {
mergeObj.audioTrack.pause();
}
return state.merge(mergeObj);
}
default: return state
}
}
В основном здесь, если audioTrack - это false, я создаю новую звуковую дорожку, когда кто-то нажимает кнопку воспроизведения. Затем я добавляю объект audioTrack в состояние редукторов. Оттуда, если дорожка установлена, я могу получить доступ к объекту audioTrack из состояния редукторов и приостановить его, если мне нужно, а также вызвать любые другие аудио методы, которые мне нужны.
Моя проблема здесь в том, что я почти уверен, что сохранение аудиообъекта в редукторе - неправильный способ приблизиться к чему-то вроде этого. Аудиообъект имеет несколько глубоко вложенных объектов, и я хотел бы, чтобы мои редукторы были как можно более плоскими по очевидным причинам производительности.
Как лучше подойти к этому? Я хотел добавить звуковой объект к объекту окна и просто сохранить его состояние там, но снова не уверен, что это наиболее разумный подход. Хотел бы, чтобы любые аудиоэлементы не попадали в дом, чтобы пользователи не могли быстро проверить элемент и найти узел вместе с его источником.
Спасибо и дайте мне знать, если что-то непонятно!
Этот ответ может вам помочь: stackoverflow.com/a/42754114/4312466



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Не храните его в состоянии redux.
Вы должны хранить минимальный объем информации об аудио. Итак, любой компонент может подписаться на это состояние. Например, создайте экземпляр аудиообъекта на componentDidMount и сохраните его в локальном состоянии, переключите аудио на getDerivedStateFromProps/componentWillReceiveProps, уничтожьте аудиообъект на componentWillUnmount и т. д.
Кроме того, если вы хотите скрыть информацию об аудио, это еще одна причина использовать локальное состояние компонента.
Я слышу ваше предложение, но все еще немного обеспокоен тем, что сохранение аудиообъекта в локальном состоянии компонента вместо редуктора Redux может по-прежнему влиять на производительность, поскольку это такой большой объект. Как вы думаете, это так? Кроме того, если я сохраняю только определенные атрибуты аудиообъекта, как я могу ссылаться на него снова, не вставляя его в DOM?
Сохранение самого аудиообъекта не влияет на производительность, независимо от того, находится ли он в хранилище Redux, в состоянии локального компонента или в поле экземпляра компонента. Однако @amankkg верен в том, что, поскольку аудиообъект не сериализуем, его фактически не следует хранить в хранилище Redux. Вам следует написать компонент React, который считывает данные из хранилища, а затем использует методы жизненного цикла React для управления императивным аудио API.
У меня была такая же проблема, и вот как я это сделал: сначала создайте аудиокомпонент вот так
import CSSModules from 'react-css-modules'
import React, { PureComponent } from 'react'
import styles from '../../app.sass'
import isUndefined from 'lodash/isUndefined'
import {connect} from "react-redux"
import {setActiveTrack} from "../../containers/Audio/actions";
class Audio extends PureComponent {
constructor (props) {
super(props)
const { src, controlsList, preload, controls, autoPlay } = props
this.state = {
src: src,
controlsList: isUndefined(controlsList) ? 'nodownload' : controlsList,
preload: isUndefined(preload) ? 'none' : preload,
controls: isUndefined(controls) ? true : controls,
autoPlay: isUndefined(autoPlay) ? false : autoPlay,
}
}
setActiveTrackHandler = () => {
const { dispatch, uid } =this.props
dispatch(setActiveTrack(uid))
}
render () {
const {uid, audioTrack} =this.props
if (this.audioRef && uid !== audioTrack) {
this.audioRef.pause()
}
return (
<audio
ref = {audio => this.audioRef = audio}
controls = {this.state.controls}
preload = {this.state.preload}
autoPlay = {this.state.autoPlay}
style = {{ width: '100%' }}
controlsList = {this.state.controlsList}
onPlay = {this.setActiveTrackHandler}
>
<source src = {this.state.src} />
</audio>
)
}
}
function mapStateToProps (state){
return {
audioTrack: state.audioReducer.audioTrack
}
}
const AudioClass = CSSModules(Audio,styles, { allowMultiple: true })
export default connect(mapStateToProps)(AudioClass)
Тогда вот ваши константы
export const SET_ACTIVE_TRACK = 'containers/Audio/SET_ACTIVE_TRACK'
А вот и ваши действия
import {
SET_ACTIVE_TRACK,
PLAY_TRACK
} from './constants'
// sets active track
export function setActiveTrack (activeTrack) {
return {
type: SET_ACTIVE_TRACK,
payload: activeTrack
}
}
а вот и редуктор
import {
SET_ACTIVE_TRACK
} from './constants'
const initialState = {
audioTrack: null,
isPlaying: false,
};
export const reducer = (state = initialState, action) => {
switch (action.type) {
case SET_ACTIVE_TRACK:
return {
...state,
audioTrack: action.payload,
}
default: return state
}
}
export default reducer
Может быть, просто сохранить идентификатор / URL-адрес аудио, а затем воспроизвести / приостановить его в своем компоненте? Зачем вообще хранить его в редукторе? Можно ли все сделать через состояние локального компонента?