Using redux-thunk, an action creator can return a function that receives dispatch (and optionally getState) to perform async operations.
Example:
const fetchData = () => {
  return async (dispatch) => {
    dispatch({ type: 'FETCH_START' });
    try {
      const res = await fetch('/api/data');
      const data = await res.json();
      dispatch({ type: 'FETCH_SUCCESS', payload: data });
    } catch (error) {
      dispatch({ type: 'FETCH_ERROR', error });
    }
  };
};