我可以派遣一个行动减速机?
是否有可能在减速器本身发出一个动作? 我有一个进度条和一个audio元素。 目标是在audio元素中更新时间时更新进度条。 但是我不知道在哪里放置ontimeupdate事件处理程序,或者如何在ontimeupdate的callback中调度一个动作来更新进度条。 这是我的代码:
//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;
在还原器中分派动作是一种反模式 。 你的reducer应该没有副作用,简单地消化动作有效载荷并返回一个新的状态对象。 在reducer中添加监听器和调度操作可能会导致链式操作和其他副作用。
听起来就像你初始化的AudioElement
类,事件监听器属于一个组件而不是状态。 在事件监听器中,你可以派发一个动作,它会更新状态。
您可以在新的React组件中初始化AudioElement
类对象,也可以AudioElement
类转换为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);
请注意, updateProgressAction
自动包装与dispatch
所以你不需要直接调用调度。
在减速机完成之前启动另一个调度是一种反模式 ,因为当减速机结束时,在减速机开始时收到的状态将不再是当前的应用程序状态。 但是从一个减速器内调度另一个调度并不是一个反模式 。 事实上,这就是Elm语言所做的,正如你所知道的,Redux是将Elm架构引入JavaScript的尝试。
这里是一个中间件,将添加属性asyncDispatch
到你所有的动作。 当reducer完成并返回新的应用程序状态时, asyncDispatch
将触发store.dispatch
并执行您给它的任何操作。
// 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(); };
现在你的减速器可以做到这一点:
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 });; } }
你可能会尝试使用一个库,如redux传奇 。 它允许一个非常干净的方式来sortingasynchronousfunction,发起行动,使用延迟等等。 这是非常强大的!