is it possible to dispatch an action in a reducer itself? I have a progressbar and an audio element. The goal is to update the progressbar when the time gets updated in the audio element. But I don't know where to place the ontimeupdate eventhandler, or how to dispatch an action in the callback of ontimeupdate, to update the progressbar. Here is my code:
//reducer
const initialState = {
audioElement: new AudioElement('test.mp3'),
progress: 0.0
}
initialState.audioElement.audio.ontimeupdate = () => {
console.log('progress', initialState.audioElement.currentTime/initialState.audioElement.duration);
//how to dispatch 'SET_PROGRESS_VALUE' now?
};
const audio = (state=initialState, action) => {
switch(action.type){
case 'SET_PROGRESS_VALUE':
return Object.assign({}, state, {progress: action.progress});
default: return state;
}
}
export default audio;
redux-loop takes a cue from Elm and provides this pattern.
Starting another dispatch before your reducer is finished is an anti-pattern, because the state you received at the beginning of your reducer will not be the current application state anymore when your reducer finishes. But scheduling another dispatch from within a reducer is NOT an anti-pattern. In fact, that is what the Elm language does, and as you know Redux is an attempt to bring the Elm architecture to JavaScript.
Here is a middleware that will add the property
asyncDispatch
to all of your actions. When your reducer has finished and returned the new application state,asyncDispatch
will triggerstore.dispatch
with whatever action you give to it.Now your reducer can do this:
You might try using a library like redux-saga. It allows for a very clean way to sequence async functions, fire off actions, use delays and more. It is very powerful!
Dispatching an action within a reducer is an anti-pattern. Your reducer should be without side effects, simply digesting the action payload and returning a new state object. Adding listeners and dispatching actions within the reducer can lead to chained actions and other side effects.
Sounds like your initialized
AudioElement
class and the event listener belong within a component rather than in state. Within the event listener you can dispatch an action, which will updateprogress
in state.You can either initialize the
AudioElement
class object in a new React component or just convert that class to a React component.Note that the
updateProgressAction
is automatically wrapped withdispatch
so you don't need to call dispatch directly.