Работа с аудиообъектами в React / Redux

В настоящее время я создаю музыкальное приложение, и у меня есть вопрос о правильном подходе к аудиообъектам с точки зрения их хранения и их текущего состояния в 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 из состояния редукторов и приостановить его, если мне нужно, а также вызвать любые другие аудио методы, которые мне нужны.

Моя проблема здесь в том, что я почти уверен, что сохранение аудиообъекта в редукторе - неправильный способ приблизиться к чему-то вроде этого. Аудиообъект имеет несколько глубоко вложенных объектов, и я хотел бы, чтобы мои редукторы были как можно более плоскими по очевидным причинам производительности.

Как лучше подойти к этому? Я хотел добавить звуковой объект к объекту окна и просто сохранить его состояние там, но снова не уверен, что это наиболее разумный подход. Хотел бы, чтобы любые аудиоэлементы не попадали в дом, чтобы пользователи не могли быстро проверить элемент и найти узел вместе с его источником.

Спасибо и дайте мне знать, если что-то непонятно!

Может быть, просто сохранить идентификатор / URL-адрес аудио, а затем воспроизвести / приостановить его в своем компоненте? Зачем вообще хранить его в редукторе? Можно ли все сделать через состояние локального компонента?

Roy Wang 10.06.2018 03:27

Этот ответ может вам помочь: stackoverflow.com/a/42754114/4312466

Jordan Enev 12.06.2018 11:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
2
2 377
2

Ответы 2

Не храните его в состоянии redux.

  1. Весь аудиообъект представляет собой информацию избыточный (имя / путь к файлу, состояние воспроизведения / паузы, достаточно информации о текущем времени).
  2. Redux и неизменяемый подход не совсем подходят для этого типа объектов с точки зрения производительности.
  3. И этот тип объектов не подходит для работы с redux dev tools / logger / человеческими глазами.

Вы должны хранить минимальный объем информации об аудио. Итак, любой компонент может подписаться на это состояние. Например, создайте экземпляр аудиообъекта на componentDidMount и сохраните его в локальном состоянии, переключите аудио на getDerivedStateFromProps/componentWillReceiveProps, уничтожьте аудиообъект на componentWillUnmount и т. д.

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

Я слышу ваше предложение, но все еще немного обеспокоен тем, что сохранение аудиообъекта в локальном состоянии компонента вместо редуктора Redux может по-прежнему влиять на производительность, поскольку это такой большой объект. Как вы думаете, это так? Кроме того, если я сохраняю только определенные атрибуты аудиообъекта, как я могу ссылаться на него снова, не вставляя его в DOM?

red house 87 12.06.2018 15:04

Сохранение самого аудиообъекта не влияет на производительность, независимо от того, находится ли он в хранилище Redux, в состоянии локального компонента или в поле экземпляра компонента. Однако @amankkg верен в том, что, поскольку аудиообъект не сериализуем, его фактически не следует хранить в хранилище Redux. Вам следует написать компонент React, который считывает данные из хранилища, а затем использует методы жизненного цикла React для управления императивным аудио API.

markerikson 12.06.2018 21:35

У меня была такая же проблема, и вот как я это сделал: сначала создайте аудиокомпонент вот так

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

Другие вопросы по теме