Can I dispatch an action in reducer?

前端 未结 4 846
暖寄归人
暖寄归人 2020-11-28 01:44

is it possible to dispatch an action in a reducer itself? I have a progressbar and an audio element. The goal is to update the progressbar when the time gets updated in the

4条回答
  •  遥遥无期
    2020-11-28 02:14

    Starting another dispatch before your reducer is finished is an anti-pattern, because the state you received at the beginning of your reducer will not be the current application state anymore when your reducer finishes. But scheduling another dispatch from within a reducer is NOT an anti-pattern. In fact, that is what the Elm language does, and as you know Redux is an attempt to bring the Elm architecture to JavaScript.

    Here is a middleware that will add the property asyncDispatch to all of your actions. When your reducer has finished and returned the new application state, asyncDispatch will trigger store.dispatch with whatever action you give to it.

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

    Now your reducer can do this:

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

提交回复
热议问题