message: Add transaction capability to asyncActions
  for relating pending/success/failure actions. Particularly useful for mapping
  a failure to a pending action to roll back any optimistic updates.
diff: @@ -31,18 +31,30 @@ limitations under the License.
  * `${id}.pending` and either
  * `${id}.success` or
  * `${id}.failure`.
  + *
  + * The shape of each are:
  + * { action: '${id}.pending', request, asyncId }
  + * { action: '${id}.success', result, asyncId }
  + * { action: '${id}.failure', err, asyncId }
  + *
  + * where `request` is returned by `pendingFn`, result
  + * is the result of the promise returned by `fn` and
  + * `asyncId` is a unique ID for each dispatch of the
  + * asynchronous action.
  */
  export function asyncAction(id, fn, pendingFn) {
  return (dispatch) => {
  + const asyncId = Math.random().toString(16).slice(2, 10);
  dispatch({
  action: id + '.pending',
  request:
  typeof pendingFn === 'function' ? pendingFn() : undefined,
  + asyncId,
  });
  fn().then((result) => {
  - dispatch({action: id + '.success', result});
  + dispatch({action: id + '.success', result, asyncId});
  }).catch((err) => {
  - dispatch({action: id + '.failure', err});
  + dispatch({action: id + '.failure', err, asyncId});
  });
  };
  }
  