GithubHelp home page GithubHelp logo

sergiodxa / use-mutation Goto Github PK

View Code? Open in Web Editor NEW
119.0 3.0 8.0 1.31 MB

🧬 Run side-effects safely in React

License: MIT License

TypeScript 100.00%
mutations reactjs hooks typescript swr react-query use-mutation side-effects

use-mutation's Introduction

🧬 useMutation - Run side-effects safely in React

CI Publish

Specially useful to run requests against an API, and combined with SWR.

Usage

Install it:

$ yarn add use-mutation

Import it:

import useMutation from 'use-mutation';

Create a function which runs a mutation

async function createComment({
  authorId,
  comment,
}: {
  authorId: number;
  comment: string;
}) {
  const res = await fetch('/api/comments', {
    method: 'POST',
    body: JSON.stringify({ authorId, comment }),
  });
  if (!res.ok) throw new Error(res.statusText);
  return await res.json();
}

Use your function with useMutation

function CommentForm({ authorId }) {
  const [comment, setComment] = React.useState('');
  const [mutate, { status }] = useMutation(createComment, {
    onMutate({ input }) {
      // do something before the mutation run
      return () => {
        // rollback changes if the mutation failed
      };
    },
    onSuccess({ data, input }) {
      // do something once the mutation succeeded
    },
    onFailure({ error, rollback, input }) {
      // do something once the mutation failed
    },
    onSettled({ status, error, data, rollback, input }) {
      switch (status) {
        case 'success': {
          // do something if the mutation succeeded
        }
        case 'failure': {
          // do something if the mutation failed
        }
      }
    },
  });

  const handleSubmit = React.useCallback(
    function handleSubmit(event) {
      mutate({ authorId, comment });
    },
    [mutate, comment]
  );

  // render your UI
}

Usage with SWR

If you are using SWR, you can use useMutation to run your mutations to perform Optimistic UI changes.

import { cache, mutate } from 'swr';

function createComment(input) {
  // ...
}

function useCreateComment() {
  return useMutation(createComment, {
    onMutate({ input }) {
      const oldData = cache.get('comment-list');
      // optimistically update the data before your mutation is run
      mutate('comment-list', current => current.concat(input), false);
      return () => mutate('comment-list', oldData, false); // rollback if it failed
    },

    onFailure({ rollback }) {
      if (rollback) rollback();
    },
  });
}

This way when you run mutate, it will first optimistically update your SWR cache and if it fails it will rollback to the old data.

API Reference

const [mutate, { status, data, error, reset }] = useMutation<
  Input,
  Data,
  Error
>(mutationFn, {
  onMutate,
  onSuccess,
  onFailure,
  onSettled,
  throwOnFailure,
  useErrorBoundary,
});

const promise = mutate(input, {
  onSuccess,
  onSettled,
  onError,
  throwOnFailure,
});

Hook Generic

Only if you are using TypeScript

  • Input = any
    • The data your mutation function needs to run
  • Data = any
    • The data the hook will return as result of your mutation
  • Error = any
    • The error the hook will return as a failure in your mutation

Hook Options

  • mutationFn(input: Input): Promise<Data>
    • Required
    • A function to be executed before the mutation runs.
    • It receives the same input as the mutate function.
    • It can be an async or sync function, in both cases if it returns a function it will keep it as a way to rollback the changed applied inside onMutate.
  • onMutate?({ input: Input }): Promise<rollbackFn | undefined> | rollbackFn | undefined
    • Optional
    • A function to be executed before the mutation runs.
    • It receives the same input as the mutate function.
    • It can be an async or sync function, in both cases if it returns a function.
    • it will keep it as a way to rollback the changed applied inside onMutate
  • onSuccess?({ data: Data, input: Input }): Promise<void> | void
    • Optional
    • A function to be executed after the mutation resolves successfully.
    • It receives the result of the mutation.
    • If a Promise is returned, it will be awaited before proceeding.
  • onFailure?({ error: Error, rollback: rollbackFn, input: Input }): Promise<void> | void
    • Optional
    • A function to be executed after the mutation failed to execute.
    • If a Promise is returned, it will be awaited before proceeding.
  • onSettled?({ status: 'success' | 'failure', error?: Error, data?: Data, rollback?: rollbackFn, input: Input}): Promise<void> | void
    • Optional
    • A function to be executed after the mutation has resolves, either successfully or as failure.
    • This function receives the error or the result of the mutation.
    • If a Promise is returned, it will be awaited before proceeding.
  • throwOnFailure?: boolean
    • Optional
    • If defined as true, a failure in the mutation will cause the mutate function to throw. Disabled by default.
  • useErrorBoundary?: boolean (default false)
    • Optional
    • If defined as true, a failure in the mutation will cause the Hook to throw in render time, making error boundaries catch the error.

Hook Returned Value

  • mutate(input: Input, config: Omit<Options<Input, Data, Error>, 'onMutate' | 'useErrorBoundary'> = {}): Promise<Data | undefined>
    • The function you call to trigger your mutation, passing the input your mutation function needs.
    • All the lifecycle callback defined here will run after the callback defined in the Hook.
  • status: 'idle' | 'running' | 'success' | 'failure'
    • The current status of the mutation, it will be:
      • idle initial status of the hook, and the status after a reset
      • running if the mutation is currently running
      • success if the mutation resolved successfully
      • failure if the mutation failed to resolve
  • data: Data
    • The data returned as the result of the mutation.
  • error: Error
    • The error returned as the result of the mutation.
  • `reset(): void
    • A function to reset the internal state of the Hook to the orignal idle and clear any data or error.

Author

License

The MIT License.

use-mutation's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar gabrielsch avatar r04423 avatar sergiodxa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

use-mutation's Issues

Be able to type multiple arguments on mutation functions

1

Above example will work but I had to set any as input.

Is your feature request related to a problem? Please describe.

  • Yes, I'm unable to type multiple input args.

Describe the solution you'd like

  • An example or api that allows for multiple args to be sent.

Describe alternatives you've considered

  • As of now only any, but maybe changing the order of the generic arguments or creating overloads could also do the trick.

Additional context
Add any other context or screenshots about the feature request here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.