I'm working on an application that plays audio clips. The audio clips that are currently playing are stored in the Redux store (you can play more than one clip at once). Everything is working just fine, but I'm wondering what the cleanest way to play/stop the audio would be. (See below JS files for the full source of my store and audio manager file)
Currently, I am triggering the play/stop actions from within the store itself, but this feels kind of wrong:
// store.js
// ...
case 'AUDIO_PLAY':
const audioObject = createAudioObject({
src: action.payload.url,
});
state.currentlyPlaying = state.currentlyPlaying.concat([audioObject]);
playAudio(audioObject);
return state;
case 'AUDIO_STOP':
state.currentlyPlaying = state.currentlyPlaying.filter(s => {
const isStoppedAudio = s._src !== action.payload;
if (isStoppedAudio) {
stopAudio(s);
}
return !isStoppedAudio;
});
return state;
Fixing the playing of audio outside of the store is pretty easy: listen to the store for any new changes, and play the sound if it is not already playing, like this:
// audio-manager.js
store.subscribe(() => {
const { currentlyPlaying } = store.getState();
for (const sound of currentlyPlaying) {
if (!sound.playing()) {
sound.play();
}
}
});
However, stopping the sound is proving to be a little trickier. Obviously, when I remove the sound from the currentlyPlaying
array, the store listener in the audio manager won't know that it needs to stop that particular audio file, because at that point, it will already be gone. This is why I am stopping the audio in the store itself before I remove it from the array. This seems counter-intuitive though, since stores should only be concerned with storing data, and not doing anything with it.
The only way I can think of keeping the stop logic in the audio manager is to create separate actions (AUDIO_STOPPING
and AUDIO_STOPPED
), and store the sound that should be stopped in another part of the state that can still be accessed in the store. After stopping the sound, it would dispatch the AUDIO_STOPPED
action that actually completely removes the audio from the state. Would this solution be more 'Redux-y' than using the store to trigger audio playing and stopping?