Relay: Promise based api for commitMutation

Created on 29 May 2017  路  11Comments  路  Source: facebook/relay

It would be nice for commitMutation to return a promise in addition to taking onCompleted and onError callbacks - this would make flow control easier w/ things like Promise.all and async / await.

commitMutation now returns a disposable - so to avoid breaking the current API it could either return something exposing a dispose method and implementing Promise, or it could return { dispose: () => void, response: Promise }.

Alternatively, it could return a promise instead of the disposable - I may be missing a use case, but it seems to me that once a mutation has been submitted to the server, reverting it on the client will not be common.

It is possible to wrap commitMutation in a straightforward way to return a promise, but I still think a promise here would be a better default.

I would be happy to put a pull together for this if it is likely to be merged.

Most helpful comment

@Makazone

import {
   commitMutation as commitMutationDefault
} from 'react-relay';

function commitMutation(environment: Environment, options: CommitMutationOptions) {
  return new Promise((resolve, reject) => {
    commitMutationDefault(environment, {
      ...options,
      onError: (error: Error) => {
        reject(error);
      },
      onCompleted: (response: object) => {
        resolve(response);
      }
    });
  });
}

Note that this uses TypeScript. You may need to remove the type annotations.

All 11 comments

Interesting. In general we've found that returning a Promise can limit the flexibility of an API, due to gaps in the spec such as support for cancellation and the fact that he function can only ever return asynchronously.

That said, mutations do seem like an area where they can be quite useful. Cancellation is useful when executing a mutation from a React component, where the mutation callbacks should not be invoked if the component is unmounted. Disposing a mutation only causes callbacks not to be fired; for consistency purposes it is still processed on the server and the cache updated.

I'm curious what others think here.

The first thing I did was wrap commitMutation() in a promise API.

Hey @miracle2k! I'm new to JS and React/Relay can you please show how did you wrap it? Sounds like a great approach for some situations.

@Makazone

import {
   commitMutation as commitMutationDefault
} from 'react-relay';

function commitMutation(environment: Environment, options: CommitMutationOptions) {
  return new Promise((resolve, reject) => {
    commitMutationDefault(environment, {
      ...options,
      onError: (error: Error) => {
        reject(error);
      },
      onCompleted: (response: object) => {
        resolve(response);
      }
    });
  });
}

Note that this uses TypeScript. You may need to remove the type annotations.

Thanks for the input here. We're currently going through old issues that appear to have gone stale (ie. not updated in about the last 3 months) because the volume of material in the issue tracker is becoming hard to manage. If this is still important to you please comment and we'll re-open this.

Thanks once again!

I would still find this very useful.

@wichert you can use relay-commit-mutation-promise.

Ditto. I've wrapped it myself, but it should really be part of the standard API IMO.

This would be helpful.

you can useMutation hook now

you most of the time you don't need a promise API for this

We use async/await in our code, so without a promise API I'm stuck wrapping the existing API myself. Here's my wrapper for useMutation, in case others find it useful:

function useAsyncMutation(mutation) {
  const [commit, isInFlight] = useMutation(mutation);
  return [
    async (args) => {
      return await new Promise((resolve, reject) => {
        commit({
          ...args,
          onCompleted: (response, errors) => {
            if (errors) {
              reject(errors[0]);
            }
            resolve(response);
          },
          onError: (error) => reject(error),
        });
      });
    },
    isInFlight,
  ];
}
Was this page helpful?
0 / 5 - 0 ratings