Search code examples
reactjsformsreact-querymutation

How to submit form with react-query


I have following code

const useCreateSupplier = (createSupplierCommand: CreateSupplierCommand) => {
  return useMutation({
    mutationFn: () =>
      axiosClient
        .post("/supplier", { createSupplierCommand })
        .then((res: AxiosResponse) => res.data),
    onSuccess: async () => {
      await queryClient.invalidateQueries({
        queryKey: [queries.get_suppliers],
      });
    },
  });
};
const CreateSupplierForm = () => {
  const useSubmit = (event: any) => {
    event.preventDefault();
    useCreateSupplier({ name: "x", website: "xxx" });
  };

  return (
    <>
      <form className="row mt-3 mb-4" onSubmit={useSubmit}>
        <div className="col-auto">
          <input type="text" className="form-control" placeholder="name" />
        </div>
        <div className="col-auto">
          <input type="text" className="form-control" placeholder="website" />
        </div>
        <div className="col-auto d-flex align-items-center">
          <button type="submit" className="btn btn-sm btn-primary">
            Add
          </button>
        </div>
      </form>
    </>
  );
};

but the page render following error

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

How can I call mutation after the form is submitted?


Solution

  • I recommend you read up on what hooks are and how to use them.

    useSubmit is not a hook and therefore it shouldn't start with the word use. I'll call it onSubmit instead.

    As the message says hooks (like useCreateSupplier) need to be called in the function body, so we move it there.

    According to the docs, useMutation returns an object, and to actually trigger the API call we need to call mutate (or mutateAsync) of that object.

    const CreateSupplierForm = () => {
       const mutation = useCreateSupplier({ name: 'x', website: 'xxx' });
    
       const onSubmit = () => {
           mutation.mutate()
       }
    
       return (
           <>
               <form className="row mt-3 mb-4" onSubmit={onSubmit}>
                   <div className="col-auto">
                       <input type="text" className="form-control" placeholder="name" />
                   </div>
                   <div className="col-auto">
                       <input type="text" className="form-control" placeholder="website" />
                   </div>
                   <div className="col-auto d-flex align-items-center">
                       <button type="submit" className="btn btn-sm btn-primary">Add</button>
                   </div>
               </form>
           </>)
    }
    

    Apart from this, to call the form with your input, you will need to do some addional changes, e.g. storing the input in some kind of state. Here's some reading on how to combine forms with Tanstack Query (React Query).