Posso inviare un’azione nel riduttore?

è ansible inviare un’azione in un riduttore stesso? Ho una barra di avanzamento e un elemento audio. L’objective è aggiornare la barra di avanzamento quando l’ora viene aggiornata nell’elemento audio. Ma non so dove posizionare l’eventhandler ontimeupdate, o come inviare un’azione nel callback di ontimeupdate, per aggiornare la barra di avanzamento. Ecco il mio codice:

//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; 

L’invio di un’azione all’interno di un riduttore è un anti-modello . Il tuo riduttore dovrebbe essere privo di effetti collaterali, semplicemente digerendo il carico utile dell’azione e restituendo un nuovo object di stato. L’aggiunta di ascoltatori e azioni di dispiegamento all’interno del riduttore può portare ad azioni concatenate e ad altri effetti collaterali.

Sembra la tua class AudioElement inizializzata e il listener di eventi appartiene a un componente anziché a uno stato. All’interno del listener di eventi è ansible inviare un’azione, che aggiornerà i progress nello stato.

È ansible inizializzare l’object class AudioElement in un nuovo componente React o semplicemente convertire tale class in un componente React.

 class MyAudioPlayer extends React.Component { constructor(props) { super(props); this.player = new AudioElement('test.mp3'); this.player.audio.ontimeupdate = this.updateProgress; } updateProgress () { // Dispatch action to reducer with updated progress. // You might want to actually send the current time and do the // calculation from within the reducer. this.props.updateProgress(); } render () { // Render the audio player controls, progress bar, whatever else return 

Progress: {this.props.progress}

; } } class MyContainer extends React.Component { render() { return } } function mapStateToProps (state) { return {}; } return connect(mapStateToProps, { updateProgressAction })(MyContainer);

Si noti che updateProgressAction viene automaticamente incluso nella dispatch quindi non è necessario chiamare direttamente la spedizione.

Iniziare un altro invio prima che il tuo riduttore sia finito è un anti-pattern , perché lo stato che hai ricevuto all’inizio del tuo riduttore non sarà più lo stato attuale dell’applicazione al termine del tuo riduttore. Ma programmare un’altra spedizione dall’interno di un riduttore NON è un anti-modello . In effetti, questo è ciò che fa il linguaggio Elm e, come sapete, Redux è un tentativo di portare l’architettura di Elm in JavaScript.

Ecco un middleware che aggiungerà la proprietà asyncDispatch a tutte le tue azioni. Quando il tuo riduttore ha terminato e restituito il nuovo stato dell’applicazione, asyncDispatch attiverà store.dispatch con qualsiasi azione tu gli dai.

 // This middleware will just add the property "async dispatch" // to actions with the "async" propperty set to true const asyncDispatchMiddleware = store => next => action => { let syncActivityFinished = false; let actionQueue = []; function flushQueue() { actionQueue.forEach(a => store.dispatch(a)); // flush queue actionQueue = []; } function asyncDispatch(asyncAction) { actionQueue = actionQueue.concat([asyncAction]); if (syncActivityFinished) { flushQueue(); } } const actionWithAsyncDispatch = Object.assign({}, action, { asyncDispatch }); next(actionWithAsyncDispatch); syncActivityFinished = true; flushQueue(); }; 

Ora il tuo riduttore può fare questo:

 function reducer(state, action) { switch (action.type) { case "fetch-start": fetch('wwww.example.com') .then(r => r.json()) .then(r => action.asyncDispatch({ type: "fetch-response", value: r })) return state; case "fetch-response": return Object.assign({}, state, { whatever: action.value });; } } 

Potresti provare a utilizzare una libreria come redux-saga . Permette un modo molto pulito per sequenziare funzioni asincrone, triggersre azioni, usare ritardi e altro. È molto potente!

redux-loop prende spunto da Elm e fornisce questo modello.