我可以在减速器中调度一个动作吗?

新手上路,请多包涵

是否可以在减速器本身中调度一个动作?我有一个进度条和一个音频元素。目标是在音频元素中的时间更新时更新进度条。但是我不知道ontimeupdate事件处理程序放在哪里,或者如何在ontimeupdate的回调中调度一个动作,来更新进度条。这是我的代码:

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

原文由 klanm 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 531
2 个回答

在 reducer 中调度动作是一种反模式。您的 reducer 应该没有副作用,只需消化操作负载并返回一个新的状态对象。在 reducer 中添加侦听器和调度操作可能会导致链接操作和其他副作用。

听起来像您初始化的 AudioElement 类和事件侦听器属于组件而不是状态。在事件侦听器中,您可以调度一个操作,该操作将更新 progress 状态。

您可以在新的 React 组件中初始化 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.updateProgressAction();
  }

  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 包装,因此您无需直接调用 dispatch。

原文由 ebuat3989 发布,翻译遵循 CC BY-SA 4.0 许可协议

在你的 reducer 完成之前开始另一个调度是一个反模式,因为当你的 reducer 完成时,你在你的 reducer 开始时收到的状态将不再是当前应用程序状态。但是 从 reducer 中安排另一个调度不是反模式。事实上,这就是 Elm 语言所做的,正如你所知,Redux 是将 Elm 架构引入 JavaScript 的尝试。

这是一个中间件,它将向您的所有操作添加属性 asyncDispatch 。当你的减速器完成并返回新的应用程序状态时, asyncDispatch 将触发 store.dispatch 无论你给它做什么。

 // This middleware will just add the property "async dispatch" to all actions
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;
};

现在你的减速器可以做到这一点:

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

原文由 Marcelo Lazaroni 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进