title: Why do we need middleware for async flow in Redux?
body: <p>According to the docs, <a href="http://redux.js.org/docs/advanced/AsyncFlow.html" rel="noreferrer">"Without middleware, Redux store only supports synchronous data flow"</a>. I don't understand why this is the case. Why can't the container component call the async API, and then <code>dispatch</code> the actions? </p>
  
  <p>For example, imagine a simple UI: a field and a button. When user pushes the button, the field gets populated with data from a remote server.</p>
  
  <p><a href="https://i.stack.imgur.com/GBI59.png" rel="noreferrer"><img src="https://i.stack.imgur.com/GBI59.png" alt="A field and a button"></a></p>
  
  <pre><code>import * as React from 'react';
  import * as Redux from 'redux';
  import { Provider, connect } from 'react-redux';
  
  const ActionTypes = {
      STARTED_UPDATING: 'STARTED_UPDATING',
      UPDATED: 'UPDATED'
  };
  
  class AsyncApi {
      static getFieldValue() {
          const promise = new Promise((resolve) =&gt; {
              setTimeout(() =&gt; {
                  resolve(Math.floor(Math.random() * 100));
              }, 1000);
          });
          return promise;
      }
  }
  
  class App extends React.Component {
      render() {
          return (
              &lt;div&gt;
                  &lt;input value={this.props.field}/&gt;
                  &lt;button disabled={this.props.isWaiting} onClick={this.props.update}&gt;Fetch&lt;/button&gt;
                  {this.props.isWaiting &amp;&amp; &lt;div&gt;Waiting...&lt;/div&gt;}
              &lt;/div&gt;
          );
      }
  }
  App.propTypes = {
      dispatch: React.PropTypes.func,
      field: React.PropTypes.any,
      isWaiting: React.PropTypes.bool
  };
  
  const reducer = (state = { field: 'No data', isWaiting: false }, action) =&gt; {
      switch (action.type) {
          case ActionTypes.STARTED_UPDATING:
              return { ...state, isWaiting: true };
          case ActionTypes.UPDATED:
              return { ...state, isWaiting: false, field: action.payload };
          default:
              return state;
      }
  };
  const store = Redux.createStore(reducer);
  const ConnectedApp = connect(
      (state) =&gt; {
          return { ...state };
      },
      (dispatch) =&gt; {
          return {
              update: () =&gt; {
                  dispatch({
                      type: ActionTypes.STARTED_UPDATING
                  });
                  AsyncApi.getFieldValue()
                      .then(result =&gt; dispatch({
                          type: ActionTypes.UPDATED,
                          payload: result
                      }));
              }
          };
      })(App);
  export default class extends React.Component {
      render() {
          return &lt;Provider store={store}&gt;&lt;ConnectedApp/&gt;&lt;/Provider&gt;;
      }
  }
  </code></pre>
  
  <p>When the exported component is rendered, I can click the button and the input is updated correctly. </p>
  
  <p>Note the <code>update</code> function in the <code>connect</code> call. It dispatches an action that tells the App that it is updating, and then performs an async call. After the call finishes, the provided value is dispatched as a payload of another action.</p>
  
  <p>What is wrong with this approach? Why would I want to use Redux Thunk or Redux Promise, as the documentation suggests?</p>
  
  <p><strong>EDIT:</strong> I searched the Redux repo for clues, and found that Action Creators were required to be pure functions in the past. For example, <a href="https://github.com/reactjs/redux/issues/533" rel="noreferrer">here's a user trying to provide a better explanation for async data flow:</a></p>
  
  <blockquote>
    <p>The action creator itself is still a pure function, but the thunk function it returns doesn't need to be, and it can do our async calls</p>
  </blockquote>
  
  <p><a href="https://github.com/reactjs/redux/issues/1088" rel="noreferrer">Action creators are no longer required to be pure.</a> So, thunk/promise middleware was definitely required in the past, but it seems that this is no longer the case?</p>