Tuesday, June 17, 2025

useSubmit() Hook in React Router

In the post Actions in React Router For Data Mutation we saw how you can create a resource (POST method) using actions and Form component in React Router. Another way (more explicit way) to submit a form is to use useSubmit() hook in React Router. In this post we'll see how to programmatically submit a form using useSubmit() hook.

useSubmit() hook in React Router

useSubmit hook returns a function.
const submit = useSubmit();

This returned function (named submit here) takes two arguments. First is the data that has to be submitted which will be wrapped as form data object. Another argument is an optional object where you can pass method with which you can specify the HTTP verb to use when the form is submitted. Supports "get", "post", "put", "delete", and "patch". Another property you can pass is action with which you can provide the URL to submit the form data to. If no action is specified, this defaults to the closest route in context.

submit(event.currentTarget, {method:"POST", action:"/post/new"});

useSubmit() hook React example

In this example we'll use an action function to create a resource. For API call https://jsonplaceholder.typicode.com/posts resource is used which is a free fake API. In the example Bootstrap 5 is used for styling. This example is same as what is already shown in this post Actions in React Router For Data Mutation except the change for programmatically submitting the form having post data using useSubmit() hook.

Component that changes is the PostForm component. Now rather than using the Form component normal <form> element is used. On submitting the form handler function is called that submits the form programmatically.

src\components\routes\PostForm.js

import { useSubmit } from "react-router";

const PostForm = () => {
   
  const submit = useSubmit();
  const formSubmitHandler = (event) => {
    event.preventDefault();
    //console.log(event.currentTarget);
    submit(event.currentTarget, {method:"POST", action:"/post/new"});
  }
  return(
    <div className="container">
      <h2>Post</h2>
      <form onSubmit={formSubmitHandler}> 
        {/* <div className="mb-2 mt-2">
            <label className="form-label" htmlFor="id">ID: </label>
            <input className="form-control" type="text" name="id" id="id" defaultValue={postData?postData.id:""}></input>
        </div> */}
        <div className="mb-2">
          <label className="form-label" htmlFor="title">Title: </label>
          <input className="form-control" type="text" name="title" id="title"></input>
        </div>
        <div className="mb-2">
          <label className="form-label" htmlFor="body">Body: </label>
          <textarea className="form-control" type="text" name="body" id="body"></textarea>
        </div>
        <div className="mb-2">
          <label className="form-label" htmlFor="userId">User ID: </label>
          <input className="form-control" type="text" name="userId" id="userId" rows="3"></input>
        </div>
        <button className="btn btn-info" type="submit">Save</button>
      </form>
    </div>
  )
}

export default PostForm;

In the handler function (formSubmitHandler()) for form submit, function returned by useSubmit hook is used to submit data. In the submit function first argument is event.currentTarget which is the form itself. As the second argument an object is passed with method and action properties. Here method value is POST and action is "/post/new" path where the action function is defined. If we don't specify action path here that will also work because action defaults to the closest route in context which is anyway "/post/new".

src\components\routes\PostAdd.js

This component is called when the route path is "/post/new".

import { redirect } from "react-router";
import PostForm from "./PostForm"

const PostAdd =() => {
  return(
    <PostForm />
  )
}

export default PostAdd;

export async function action({request, params}){
  const data = await request.formData();
  const postData = {
    title:data.get("title"),
    body:data.get("body"),
    userId:data.get("userId")
  }
  const response = await fetch('https://jsonplaceholder.typicode.com/posts', 
    {
      method: 'POST', 
      headers: {                
          'Content-type': 'application/json',                 
      },
      body: JSON.stringify(postData)
    },
      
  );
  if(!response.ok){
    throw new Response('Error while saving post data', {status:500});
  } 
  const responseData = await response.json();
  //console.log(responseData);
  return redirect('/post');
}

Some of the points to note here-

  1. Action function receives an object that has properties like request, params.
  2. Request object has a method formData() that returns form data.
  3. On that data object you can call get() method to get the form field value by passing the form field name. The name you pass in get method should match the name you gave in the input element with in the form. Refer PostForm to check the name attribute in each input element.
  4. With action function or loader function it is recommended to use redirect function rather than useNavigate to navigate to another page. That’s what is done here, if post is added successfully redirect to “/post” path.

That's all for this topic useSubmit() Hook in React Router. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Data Loader With Dynamic Routes in React
  2. useRouteLoaderData() Hook in React Router
  3. Using NavLink in React Router
  4. Index Route in React Router

You may also like-

  1. JVM Run-Time Data Areas - Java Memory Allocation
  2. Difference Between Abstract Class And Interface in Java
  3. Armstrong Number or Not Java Program
  4. Spring Boot + Data JPA + MySQL REST API CRUD Example

No comments:

Post a Comment