script react open helmet change reactjs redux reducers

reactjs - react - ¿Puedo enviar una acción en reductor?



react open graph (4)

¿Es posible despachar una acción en un reductor? Tengo una barra de progreso y un elemento de audio. El objetivo es actualizar la barra de progreso cuando el tiempo se actualiza en el elemento de audio. Pero no sé dónde colocar el controlador de eventos ontimeupdate, ni cómo enviar una acción en la devolución de llamada de ontimeupdate, para actualizar la barra de progreso. Aquí está mi código:

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


Puede intentar usar una biblioteca como redux-saga . Permite una forma muy limpia de secuenciar funciones asíncronas, disparar acciones, usar retrasos y más. Es muy poderoso!


redux-loop toma una señal de Elm y proporciona este patrón.


El envío de una acción dentro de un reductor es un antipatrón . Su reductor no debe tener efectos secundarios, simplemente digiere la carga útil de la acción y devuelve un nuevo objeto de estado. Agregar oyentes y enviar acciones dentro del reductor puede conducir a acciones encadenadas y otros efectos secundarios.

Parece que la clase de AudioElement inicializada y el detector de eventos pertenecen a un componente en lugar de estar en estado. Dentro del detector de eventos puede enviar una acción, que actualizará el progress en el estado.

Puede inicializar el objeto de clase AudioElement en un nuevo componente React o simplemente convertir esa clase en 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 <p>Progress: {this.props.progress}</p>; } } class MyContainer extends React.Component { render() { return <MyAudioPlayer updateProgress={this.props.updateProgress} /> } } function mapStateToProps (state) { return {}; } return connect(mapStateToProps, { updateProgressAction })(MyContainer);

Tenga en cuenta que updateProgressAction se envuelve automáticamente con el dispatch por lo que no necesita llamar al despacho directamente.


Iniciar otro despacho antes de que termine su reductor es un antipatrón , porque el estado que recibió al comienzo de su reductor ya no será el estado actual de la aplicación cuando finalice su reductor. Pero programar otro despacho desde un reductor NO es un antipatrón . De hecho, eso es lo que hace el lenguaje Elm, y como saben, Redux es un intento de llevar la arquitectura Elm a JavaScript.

Aquí hay un middleware que agregará la propiedad asyncDispatch a todas sus acciones. Cuando su reductor haya finalizado y devuelto el nuevo estado de la aplicación, asyncDispatch activará store.dispatch con cualquier acción que le dé.

// 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 }); const res = next(actionWithAsyncDispatch); syncActivityFinished = true; flushQueue(); return res; };

Ahora su reductor puede hacer esto:

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 });; } }