Skip to content

Latest commit

 

History

History

react-use-mutation

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

React mutation hook

Minimal asynchronous data create/update/delete hook.

This hook is suitable for operations which may be non-safe due to side effects (eg. POST, PUT, PATCH, and DELETE requests).

Inspired by (and API compatible with) React Query's useMutation hook.

It includes:

  • Simplified mutation results:
    • data
    • error
    • isLoading
    • mutate()

It does not include:

  • Mutation Options
  • Retrying
  • Caching

This mutation hook implementation is so simple, there's just not any reason to have options.

Retrying may be useful, but there's no reason to build it in to a mutation hook. Just retry in the mutation function as needed. Retrying un-safe operations can be dangerous if done incorrectly!

Mutations usually aren't cached. Not including the option to cache in the mutation hook avoids the need for a QueryClient context, which simplifies setup and testing.

The useMutation hook can be used directly in components, but generally you should wrap it in a custom hook.

const useCreateResource = (): MutationResult<Resource> => {
  const result = useMutation(
    // Mutation functions are always asynchronous. The most up-to-date
    // function will be used when `result.mutate()` is called.
    async (resource: Resource): Resource => {
      const response = await fetch('https://...', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(resource),
      });

      if (!response.ok) {
        throw new Error(`Request failed (status: ${response.status})`);
      }

      return response.json();
    },
  );

  return result;
};

Use your custom mutation hook in a component.

const Component = (props: Props): JSX.Element => {
  const { data, error, isLoading, mutate } = useCreateResource();
  const onSave = useCallback((resource: Resource) => {
    mutate(resource)
  }, [mutate]);

  return (
    <div>
      {isLoading && <Saving />}
      {error && <Error error={error} />}
      {data && <Success data={data} />}
      <CreateResourceForm enabled={!isLoading} onSave={onSave} />
    </div>
  )
};