Next.js multi step form with routing

Viewed 3045

My Next.js multistep form works just fine, switching between steps all on one page index.js

return (
    <div>
      <Head>
        <title>Next.js Multi Step Form</title>
      </Head>
      < Navbar />
        <div className={styles.container}>
          <FormCard>
            {formStep >= 0 && (
              <ContractInfo
                formStep={formStep}
                prevFormStep={prevFormStep}
                nextFormStep={nextFormStep}
              />
            )}
            {formStep >= 1 && (
              <PersonalInfo
                formStep={formStep}
                prevFormStep={prevFormStep}
                formStepToLast={formStepToLast}
              />
            )}
            {formStep >= 2 && (
              <ConfirmPurchase
                formStep={formStep}
                prevFormStep={prevFormStep}
                nextFormStep={nextFormStep}
              />

            )}
          </FormCard>
        </div>
    </div>
  );

UPDATE

After trying out the below suggestions, I ended up having my path updated. I also simplifies my code (hardcoded), as I only have two steps. The current code for the index.js looks the following:

const App = () => {
  const router = useRouter();
  const [formStep, setFormStep] = useState(0);
  const { setFormValues } = useContext(FormContext);

  useEffect(() => { router.push(`/?step=${formStep}`), setFormStep(formStep) }, [formStep]);
  
  const nextFormStep = (contract='') => {
    setFormStep(1);
    setFormValues({ contract });
  };


  const prevFormStep = () => {
    setFormStep((formStep) => formStep - 1);
    
  };

  const formStepToLast = () => {
    setFormStep(2);
  };

  return (
    <div>
      <Head>
        <title>Next.js Multi Step Form</title>
      </Head>
      < Navbar />
        <div className={styles.container}>
            {formStep >= 0 && (
              <ContractInfo
                formStep={formStep}
                prevFormStep={prevFormStep}
                nextFormStep={nextFormStep}
              />
            )}
            {formStep >= 1 && (
              <PersonalInfo
                formStep={formStep}
                prevFormStep={prevFormStep}
                formStepToLast={formStepToLast}
              />
            )}
            {formStep >= 2 && (
              <ConfirmPurchase
                formStep={formStep}
                prevFormStep={prevFormStep}
                nextFormStep={nextFormStep}
              />
            )}  
        </div>
    </div>
  );
};

export default App;

Still, I am not managing to navigate through form with the browser Back / Next buttons. It will change the path, but won't render the corresponding component. I assume, it hast smth. to do with the State. If I set useState to (1), it will render the right corresponding component under http://localhost:3000/?step=1, so, it does save the state. However navigating with the browser Buttons is impossible.

1 Answers

You can use a query parameter to set the formStep and router.push to handle the form steps within the same page but have different URLs displayed.

import { useRouter } from 'next/router';

export default function IndexPage() {
    const router = useRouter();
    const formStep = router.query.step ?? 0;

    // Remaining JSX code
}

Then, on the action to go to the first form step you can call something like the following.

router.push('/?step=1', '/personal_info');

This will update the URL on the browser and re-render the page with the formStep >= 1 components visible.

Here's a codesandbox with a simplified version of your logic.

Related