I built a multilevel form using this css-tricks article and I am trying to validate the form using react-hook-form
, but the react-hook-form
only sees the step3 inputs data, and I need all the input data from step1 to step3 so I can validate and send to the server. It is a simple registration form for a web app.
import React, { useState } from "react"
import { Link } from "gatsby"
import { useForm } from "react-hook-form"
import { FormTitle } from "../components/input"
import { StepOne, StepTwo, StepThree } from "../components/joinFormSteps"
export default function () {
const [currentStep, setCurrentStep] = useState(1)
const { register, handleSubmit } = useForm()
const _next = () => {
// If the current step is 1 or 2, then add one on "next" button click
setCurrentStep(currentStep >= 2 ? 3 : currentStep + 1)
}
const _prev = () => {
// If the current step is 2 or 3, then subtract one on "previous" button click
setCurrentStep(currentStep <= 1 ? 1 : currentStep - 1)
}
const previousButton = () => {
if (currentStep !== 1) {
return (
<button className={styles.join__nxtbutton} type="button" onClick={_prev}>
Previous
</button>
)
}
// ...else return nothing
return null
}
const nextButton = () => {
if (currentStep < 3) {
return (
<button
className={`${styles.join__nxtbutton} ${
currentStep === 1 ? styles.join__btnMarginRightZero : ""
} `}
type="button"
onClick={_next}
>
Next
</button>
)
}
if (currentStep === 3) {
return (
<input
className={`${styles.join__nxtbutton} ${
currentStep === 1 ? styles.join__btnMarginRightZero : ""
} `}
type="submit"
name="submit"
value="Join Now"
/>
)
}
// ...else render nothing
return null
}
const onSubmit = data => {
console.log(data)
}
return (
<div className={styles.join}>
<FormTitle title="Become a member" />
<form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
<StepOne currentStep={currentStep} register={register} />
<StepTwo currentStep={currentStep} register={register} />
<StepThree currentStep={currentStep} register={register} />
<div className={styles.join__buttonArea}>
<Link to="/sign-in" className={styles.join__link}>
Sign in instead
</Link>
<div>
{previousButton()}
{nextButton()}
</div>
</div>
</form>
</div>
)
}
Implementation
import React from "react"
import { Input, SelectInput, CheckboxInput } from "../components/input"
import states from "../assets/nigeria-states.json"
import styles from "./joinFormSteps.module.scss"
export function StepOne({ currentStep, register }) {
if (currentStep !== 1) {
return null
}
return (
<React.Fragment>
<div className={styles.form__row}>
<div className={styles.form__input}>
<Input
label="Firstname*"
name="firstname"
type="text"
placeholder="Firstname"
register={register}
/>
</div>
<div className={styles.form__input}>
<Input
label="Lastname*"
name="lastname"
type="text"
placeholder="Lastname"
register={register}
/>
</div>
</div>
<div className={styles.form__input}>
<Input
label="Email*"
name="email"
type="email"
placeholder="[email protected]"
register={register}
/>
</div>
<div className={styles.form__row}>
<div className={styles.form__input}>
<Input
label="Password*"
name="password"
type="password"
placeholder="Password"
register={register}
/>
</div>
<div className={styles.form__input}>
<Input
label="Confirm Password*"
name="confPassword"
type="password"
placeholder="Confirm Password"
register={register}
/>
</div>
</div>
</React.Fragment>
)
}
export function StepTwo({ currentStep, register }) {
if (currentStep !== 2) {
return null
}
return (
<React.Fragment>
<div className={styles.form__row}>
<div className={styles.form__input}>
<Input
label="Address*"
name="address"
type="text"
placeholder=""
register={register}
/>
</div>
<div className={styles.form__input}>
<Input label="City*" name="city" type="text" placeholder="" register={register} />
</div>
</div>
<div className={styles.form__row}>
<div className={styles.form__input}>
<SelectInput label="State*" name="state" options={states} register={register} />
</div>
<div className={styles.form__input}>
<Input
label="Postal code"
name="postalCode"
type="text"
placeholder=""
register={register}
/>
</div>
</div>
<div className={styles.form__input}>
<Input
label="Phone Number*"
name="number"
type="number"
placeholder="Phone Number"
register={register}
/>
</div>
</React.Fragment>
)
}
export function StepThree({ currentStep, register }) {
if (currentStep !== 3) {
return null
}
return (
<React.Fragment>
<div className={styles.form__input}>
<SelectInput
label="Membership type*"
name="memberType"
options={[
{ code: 1, name: "Associate Membership" },
{ code: 2, name: "Full Membership" },
]}
register={register}
/>
</div>
<div className={styles.form__input}>
<CheckboxInput
label="How do you identify yourself*"
options={[
{ name: "author", value: "An Author" },
{ name: "illustrator", value: "An Illustrator" },
]}
register={register}
/>
</div>
</React.Fragment>
)
}
The problem here is in this code below:
Once you press the next button, you go to the next step.
StepOne
component then returnsnull
which make the children components unmounted and unregister your fields.To solve this issue, you must not unmount the components when jumping between steps. You can do that by hiding the component when you don't want to display it. So try changing your code to this:
Live Demo