DEV Community

Cover image for Handling React Form Submit with Redirect & Async/Await for Beyond Beginners
Brad Beggs
Brad Beggs

Posted on

Handling React Form Submit with Redirect & Async/Await for Beyond Beginners

Who This Is for

  • You have a functioning async/await fetch helper function to POST/GET/PATCH/etc.
  • Upon successful submission, you want to redirect the user to another page.
  • You are using functional components (i.e. not a class component).
  • You have a working form, meaning, at a minimum, you can console.log(someFormData) inside the handleSubmit() function.
  • Already using React-Router-Dom for navigation and links

Step 1 - Your async/await is in a Helper Function/File

Place your FETCH function(s) in an ./api/fetch.js file for easy reuse.

Step 2 - Call Your Helper Function From handleSubmit()

For this tutorial, I’m using a POST function call inside the handleSubmit():

function handleSubmit(event){
    event.preventDefault()

    let token = // unimportant code handling getting a token 

   // helper function from the fetch API class, located in another file
    Api.addIncidentAsync(
     token,  
     values.title  // from state using hooks
     )
      // can the redirect go here??
    }
Enter fullscreen mode Exit fullscreen mode

Though the nested fetch function inside Api.addIncidentAsync() won’t return a pendingPromise because of async/await, the Api.addIncidentAsync() itself does return a pendingPromise since Javascript can/does run asynchronously.

This means if your redirect url is created from the FETCH response, your redirect will execute before the Api.addIncidentAsync() resolves since Javascript runs both Api.addIncidentAsync() and redirect effectively at the same time.

TL:DR No, you can’t create a dynamic URL redirect in the above comment location. It is a timing issue between a redirect and Api.addIncidentAsync() resolving.

Step 3 - Chain .then() to Your FETCH Helper Function

To fix the timing issue, add .then() to the end of your helper function.

Now the handleSubmit() looks like this:

function handleSubmit(event){
    event.preventDefault()

    let token = // unimportant code for getting a token 

    // helper function from the fetch API class 
    Api.addIncidentAsync(
      token,  
      value.title  // from state
     ).then(response => {
         // redirect code here
      }
    }
Enter fullscreen mode Exit fullscreen mode

The code in .then() only runs once the promise resolves from Api.addIncidentAsync().

Step 4 - React-Router-Dom Hooks: useHistory() to history.push() a Redirect

In React 16.8 useHistory() hook from React-Router-Dom lets you manipulate the browser DOM history. Read more on the History object

useHistory() requires a React Component (arrow function or regular function with CapitalizedName), not a class component, to work (per the Rules of Hooks)

import { useHistory } from "react-router-dom";
import Api from '../api';

function IncidentForm(){
  const [values, setValues] = useState(initialValues); // using hooks for form state

  let history = useHistory();  // declare here, inside a React component. 

  const handleInputChange = (event)=>{ 
    // unimportant code
  }

  function handleSubmit(event){
    event.preventDefault()

    let token =  // unimportant code for getting a token 


    Api.addIncidentAsync(
      token,
      value.title  // from state 
     ).then(response => {
       let url = response.data.id + //string to build URL
       history.push(url)  // redirect
      })
    }

// more form code below, not included 
Enter fullscreen mode Exit fullscreen mode

Step 5 - Error Handling

No error handling is included for simplicity. Make sure to include error handling in your code.

Feedback?

Have thoughts on async/await or the above implementation? In particular, is it possible to drop the use of .then()?

If so, drop a note. I'd love to hear and see your examples, explanations, and other details to clarify how/why/when.

Resources

React Components
React Router Hooks
Rules of Hooks
Functional Components vs Classes
Async/Await & Promise - Straightforward Explanation

Top comments (3)

Collapse
 
lamia_z profile image
Mihoubi Lamia Zohra

In react-router-dom v6 useHistory was replaced with useNavigate. Here's the code that solved the issue for me:

import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
const onSubmit = () => {
    e.preventDefault();
    // do what you want with your form data
    navigate('/my-path');
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
rickystam profile image
Ricky Stam

A nice addition to your example would be to show how to handle 302 Redirect Http response from server

Collapse
 
brad_beggs profile image
Brad Beggs

That'll be a brave new frontier for me; haven't yet dealt with a 302 server response.