我可以在减速机中发送动作吗?

kla*_*anm 171 reducers reactjs redux

是否可以在减速机本身发送动作?我有一个进度条和一个音频元素.目标是在音频元素中更新时间时更新进度条.但是我不知道将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;
Run Code Online (Sandbox Code Playgroud)

ebu*_*989 133

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

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

您可以AudioElement在新的React组件中初始化类对象,也可以只将该类转换为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);
Run Code Online (Sandbox Code Playgroud)

请注意,它updateProgressAction会自动包装,dispatch因此您无需直接调用dispatch.

  • 你的例子中定义的符号`updateProgressAction`在哪里? (5认同)
  • 如果您不应该在reducer内调度动作,那么redux-thunk是否违反了redux的规则? (2认同)
  • @EricWiener 我相信“redux-thunk”正在从另一个操作而不是减速器分派一个操作。/sf/ask/2478799641/#35415559 (2认同)

Mar*_*oni 129

在减速器完成之前开始另一次调度是一种反模式,因为当您的减速器完成时,您在减速器开始时收到的状态将不再是当前的应用状态.但是在reducer中安排另一个调度并不是反模式.事实上,这就是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 });

  const res = next(actionWithAsyncDispatch);

  syncActivityFinished = true;
  flushQueue();

  return res;
};
Run Code Online (Sandbox Code Playgroud)

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

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 });;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 您实际上是在您的减速器中进行 HTTP API 调用,声称这是*正确的*做法,同时将某些内容描述为_反模式_?什么!?你不应该做任何会对你的减速函数产生副作用的事情!这是 Redux 101:[Redux 基础知识,第 6 部分:异步逻辑和数据获取](https://redux.js.org/tutorials/fundamentals/part-6-async-logic) (我不明白这个答案得到了这么多的赞成票,而且这么多年以来没有人呼吁它。我是不是错过了什么?) (8认同)
  • Marcelo,你的博客文章在描述你的方法的情况方面做得很好,所以我在这里链接到它:https://lazamar.github.io/dispatching-from-inside-of-reducers/ (6认同)
  • 这正是我所需要的,除了中间件as-is中断`dispatch`,它应该返回动作.我将最后一行更改为:`const res = next(actionWithAsyncDispatch); syncActivityFinished = true; flushQueue(); 返回res;`它工作得很好. (3认同)
  • 如果您不应该在 reducer 中调度 action,那么 redux-thunk 是否违反了 redux 的规则? (3认同)

cha*_*vdw 11

您可以尝试使用像redux-saga这样的库.它允许以非常简洁的方式对异步函数进行排序,触发操作,使用延迟等.它非常强大!

  • 您能指定如何使用 redux-saga 实现“在 reducer 内调度另一个调度”吗? (3认同)
  • 例如,假设您有一个商品商店,您已在其中加载了部分商品。项目是延迟加载的。假设一个物品有一个供应商。供应商也懒惰地装货。因此,在这种情况下,可能存在其供应商尚未加载的项目。在item-reducer中,如果我们需要获取尚未加载的item的信息,我们必须通过reducer再次从服务器加载数据。在这种情况下,redux-saga 在减速器内部如何提供帮助? (2认同)

Qua*_*Van 5

redux-loop从Elm那里得到提示,并提供了这种模式。