您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

SoundCollection.js 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // @flow
  2. import React, { Component } from 'react';
  3. import { Audio } from '../../media';
  4. import type { AudioElement } from '../../media';
  5. import { connect } from '../../redux';
  6. import { _addAudioElement, _removeAudioElement } from '../actions';
  7. import type { Sound } from '../reducer';
  8. /**
  9. * {@link SoundCollection}'s properties.
  10. */
  11. type Props = {
  12. /**
  13. * Dispatches {@link _ADD_AUDIO_ELEMENT} Redux action which will store the
  14. * {@link AudioElement} for a sound in the Redux store.
  15. */
  16. _addAudioElement: Function,
  17. /**
  18. * Dispatches {@link _REMOVE_AUDIO_ELEMENT} Redux action which will remove
  19. * the sound's {@link AudioElement} from the Redux store.
  20. */
  21. _removeAudioElement: Function,
  22. /**
  23. * It's the 'base/sounds' reducer's state mapped to a property. It's used to
  24. * render audio elements for every registered sound.
  25. */
  26. _sounds: Map<string, Sound>
  27. }
  28. /**
  29. * Collections of all global sounds used by the app for playing audio
  30. * notifications in response to various events. It renders <code>Audio</code>
  31. * element for each sound registered in the base/sounds feature. When the audio
  32. * resource is loaded it will emit add/remove audio element actions which will
  33. * attach the element to the corresponding {@link Sound} instance in the Redux
  34. * state. When that happens the sound can be played using the {@link playSound}
  35. * action.
  36. */
  37. class SoundCollection extends Component<Props> {
  38. /**
  39. * Implements React's {@link Component#render()}.
  40. *
  41. * @inheritdoc
  42. * @returns {ReactElement}
  43. */
  44. render() {
  45. let key = 0;
  46. const sounds = [];
  47. for (const [ soundId, sound ] of this.props._sounds.entries()) {
  48. const { options, src } = sound;
  49. sounds.push(
  50. React.createElement(
  51. Audio, {
  52. key,
  53. setRef: this._setRef.bind(this, soundId),
  54. src,
  55. loop: options.loop
  56. }));
  57. key += 1;
  58. }
  59. return sounds;
  60. }
  61. /**
  62. * Set the (reference to the) {@link AudioElement} object which implements
  63. * the audio playback functionality.
  64. *
  65. * @param {string} soundId - The sound Id for the audio element for which
  66. * the callback is being executed.
  67. * @param {AudioElement} element - The {@link AudioElement} instance
  68. * which implements the audio playback functionality.
  69. * @protected
  70. * @returns {void}
  71. */
  72. _setRef(soundId: string, element: ?AudioElement) {
  73. if (element) {
  74. this.props._addAudioElement(soundId, element);
  75. } else {
  76. this.props._removeAudioElement(soundId);
  77. }
  78. }
  79. }
  80. /**
  81. * Maps (parts of) the Redux state to {@code SoundCollection}'s props.
  82. *
  83. * @param {Object} state - The redux state.
  84. * @private
  85. * @returns {{
  86. * _sounds: Map<string, Sound>
  87. * }}
  88. */
  89. function _mapStateToProps(state) {
  90. return {
  91. _sounds: state['features/base/sounds']
  92. };
  93. }
  94. /**
  95. * Maps dispatching of some actions to React component props.
  96. *
  97. * @param {Function} dispatch - Redux action dispatcher.
  98. * @private
  99. * @returns {{
  100. * _addAudioElement: void,
  101. * _removeAudioElement: void
  102. * }}
  103. */
  104. export function _mapDispatchToProps(dispatch: Function) {
  105. return {
  106. /**
  107. * Dispatches action to store the {@link AudioElement} for
  108. * a {@link Sound} identified by given <tt>soundId</tt> in the Redux
  109. * store, so that the playback can be controlled through the Redux
  110. * actions.
  111. *
  112. * @param {string} soundId - A global identifier which will be used to
  113. * identify the {@link Sound} instance for which an audio element will
  114. * be added.
  115. * @param {AudioElement} audioElement - The {@link AudioElement}
  116. * instance that will be stored in the Redux state of the base/sounds
  117. * feature, as part of the {@link Sound} object. At that point the sound
  118. * will be ready for playback.
  119. * @private
  120. * @returns {void}
  121. */
  122. _addAudioElement(soundId: string, audioElement: AudioElement) {
  123. dispatch(_addAudioElement(soundId, audioElement));
  124. },
  125. /**
  126. * Dispatches action to remove {@link AudioElement} from the Redux
  127. * store for specific {@link Sound}, because it is no longer part of
  128. * the DOM tree and the audio resource will be released.
  129. *
  130. * @param {string} soundId - The id of the {@link Sound} instance for
  131. * which an {@link AudioElement} will be removed from the Redux store.
  132. * @private
  133. * @returns {void}
  134. */
  135. _removeAudioElement(soundId: string) {
  136. dispatch(_removeAudioElement(soundId));
  137. }
  138. };
  139. }
  140. export default connect(_mapStateToProps, _mapDispatchToProps)(SoundCollection);