Redirect to website after form submit in react

Viewed 1138

I know this question has been asked a million times, though I still struggle to transfer the answers to my case. The answer is probably trivial to a more experienced person. I am super new to react. I would like to redirect to '/' after the form was successfully submitted. I tried to modify handleSubmit accordingly, but none of my trails was successful. The problem is that the user has no idea that the message has been send and after submit the message is still in the form. So, I simply would like to redirect to the root.

This is my component:


import React from "react";
import { ChatIcon } from "@heroicons/react/solid";
import { useHistory } from "react-router-dom";

export default function Contact() {
  const [name, setName] = React.useState("");
  const [email, setEmail] = React.useState("");
  const [message, setMessage] = React.useState("");
  const history = useHistory() 
  
  function encode(data) {
    return Object.keys(data)
      .map(
        (key) => encodeURIComponent(key) + "=" + encodeURIComponent(data[key])
      )
      .join("&");
  }

  function handleSubmit(e) {
    e.preventDefault();
    fetch("/", {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: encode({ "form-name": "contact", name, email, message }),
    })
      .then(() => {
        console.log('Email sent');
        history.push('/');
      })
      .catch((error) => console.log(error));
  }

  return (
    <section id="contact" className="relative">
      <div className="container px-5 pt-20 pb-0 mx-auto text-center">
      <ChatIcon className="w-10 inline-block mb-4" />

        <h1 className="sm:text-4xl text-3xl font-medium title-font text-white mb-4">
              Get in touch
        </h1>
        <p className="text-base leading-relaxed xl:w-2/4 lg:w-3/4 mx-auto">
            You have ideas about collaborations or questions about my latest projects? Feel free to reach out!<br/> I am happy to talk. 
        </p>        
      </div>
      <div className="container px-5 pb-10 mx-auto flex sm:flex-nowrap flex-wrap">
        <form
          netlify
          data-netlify-recaptcha="true"
          data-netlify="true"
          netlify-honeypot="bot-field"
          name="contact"
          onSubmit={handleSubmit}
          className="lg:w-1/3 md:w-1/2 flex flex-col md:ml-auto w-full md:py-8 mt-8 md:mt-0">
          
          <input type="hidden" name="form-name" value="contact" />

          <div className="relative mb-4">
            <label htmlFor="name" className="leading-7 text-sm text-gray-400">
              Name
            </label>
            <input
              type="text"
              id="name"
              name="name"
              className="w-full bg-gray-800 rounded border border-gray-700 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-900 text-base outline-none text-gray-100 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
              onChange={(e) => setName(e.target.value)}
            />
          </div>
          <div className="relative mb-4">
            <label htmlFor="email" className="leading-7 text-sm text-gray-400">
              Email
            </label>
            <input
              type="email"
              id="email"
              name="email"
              className="w-full bg-gray-800 rounded border border-gray-700 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-900 text-base outline-none text-gray-100 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"
              onChange={(e) => setEmail(e.target.value)}
            />
          </div>
          <div className="relative mb-4">
            <label
              htmlFor="message"
              className="leading-7 text-sm text-gray-400">
              Message
            </label>
            <textarea
              id="message"
              name="message"
              className="w-full bg-gray-800 rounded border border-gray-700 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-900 h-32 text-base outline-none text-gray-100 py-1 px-3 resize-none leading-6 transition-colors duration-200 ease-in-out"
              onChange={(e) => setMessage(e.target.value)}
            />
          </div>
          <div data-netlify-recaptcha="true" class="form-row"></div>
          <button
            type="submit"
            className="text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg">
            Submit
          </button>
        </form>

        <div className="lg:w-2/3 md:w-1/2 bg-gray-900 rounded-lg overflow-hidden sm:ml-10 p-10 flex items-end justify-start relative mt-10">
          <iframe
            width="100%"
            height="100%"
            title="map"
            className="absolute inset-0"
            frameBorder={0}
            marginHeight={0}
            marginWidth={0}
            style={{ filter: "opacity(0.7)" }}
            src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d109162.25531026715!2d-114.16629014851806!3d51.041178754239546!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x53717db7481cb3b1%3A0x36aff4a9e3c803fb!2sUniversity%20of%20Calgary!5e0!3m2!1sen!2sca!4v1629156439590!5m2!1sen!2sca"
          />
          <div className="bg-gray-900 relative flex flex-wrap py-6 rounded shadow-md">
            <div className="lg:w-1/2 px-6">
              <h2 className="title-font font-semibold text-white tracking-widest text-xs">
                ADDRESS
              </h2>
              <p className="mt-1">
                2500 University Dr NW, T2N 1N4, Calgary, AB, Canada
              </p>
            </div>
            <div className="lg:w-1/2 px-6 mt-4 lg:mt-0">
              <h2 className="title-font font-semibold text-white tracking-widest text-xs">
                EMAIL
              </h2>
              <a className="text-indigo-400 leading-relaxed" href='mailto:swacker@ucalgary.ca'>
                swacker@ucalgary.ca
              </a>
              <h2 className="title-font font-semibold text-white tracking-widest text-xs mt-4">
                LINKED IN
              </h2>
              <p className="leading-relaxed"><a href='https://www.linkedin.com/in/sorenwacker/'>sorenwacker</a>   </p>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

I found solutions with the browser history and with Redirect and with a redirect variable. Though, I am not sure what is the best way.

5 Answers

From react-router-dom you can import the hook useHistory. Then do something like this:

const history = useHistory();

const handleSubmit = (e) => {
    // your submit logic ...

    history.push("/");
}

you can do a button that appears directly after the user submitted the form you can name it Ok or something like this and after clicking it will redirect to '/'

OR

if you want to make it automatic after the user submits the form and show him a message for a specific amount of time and after that, the user will be redirected to '/'. you need to use settimeout function and you can add it after you get the response from your backend

You only need a minor change to your code.

You need a Router component that wraps your Contact component in your parent component (or higher up in your component tree). This'll make useHistory() work otherwise you'll end up with "Cannot read property 'history' of undefined" in your Contact component.

import { BrowserRouter as Router } from 'react-router-dom';
// import { HashRouter as Router } from 'react-router-dom'; If you use HashRouter

const App = () => (
<Router>
  <Contact/>
</Router>
)

If you already have a Router component make sure your Contact component is a child/decendant of that component.

Example here: https://codesandbox.io/s/react-boilerplate-forked-h4bme

This is a minimum example on how to make the code in the question work. For your complete app you'll also need to configure your Router and define Routes. More info here: https://reactrouter.com/web/guides/quick-start

When you call fetch('/', ...) you are effectively requesting http://yourdomain.com/. You have added the POST method option. Making a post request to your root domain is possible, but I would personally avoid this. Often servers will have an /api route in which all API routes are appended.

There is no information provided about the api routes available in your project, but I would advice double checking if the route provided is indeed correct.

Also, when exactly do you want to redirect the user?

In your current setup history.push('/'); is called inside the .then callback. This makes it so that the fetch call needs to succeed in order to redirect. This is viable, but not the only option.

If you want to ALWAYS redirect the user after having clicked the button in the form, consider adding a .finally to your Promise chain. It is always advisable to take into account that api routes may fail, redirecting a user when it has not been successfully submitted to the server is probably not desired, but at least you will always be redirected ;).

Example with finally:

fetch("/", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: encode({ "form-name": "contact", name, email, message }),
})
  .then(() => {
    console.log('Email sent');
  })
  .catch((error) => {
    console.log(error);
  })
  .finally(() => {
    history.push('/');
  });

Make sure you have configured your routes the correct way.

import React from 'react';
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';

export const history = createBrowserHistory();

export const App: React.FC = () => {
  return (
      <Router history={history}>
        <Header />
        <Routes /> // Your all routes
      </Router>
  );
};

history will help you out used anywhere to push the router. In your components and utils.

history.push('/somewhere');

history.push({
  pathname: '/somewhere',
  search: '?some=search-string',
  hash: '#something',
  state: {
    [userDefined]: true
  }
});

You can also use useHistory() hooks as well.

const history = useHistory();

const handleSubmit = (e) => {
    // do some stuff
    history.push("/");
}
Related