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 thehandleSubmit()
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??
}
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
}
}
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
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)
In react-router-dom v6
useHistory
was replaced withuseNavigate
. Here's the code that solved the issue for me:A nice addition to your example would be to show how to handle 302 Redirect Http response from server
That'll be a brave new frontier for me; haven't yet dealt with a 302 server response.