我正在尝试使用 formik 库在 nextjs 中实现多步骤表单。一切似乎都很好,除了当用户单击后退按钮时表单由于状态更改而重置。有没有办法实现表单中所有步骤的重新渲染而不需要清除输入字段的数据?我希望当用户单击表单最后一步的提交按钮时进行表单重置。
这是我的渲染代码:
import QuoteStep1 from '../components/QuoteStep1'
import QuoteStep2 from '../components/QuoteStep2'
import QuoteStep3 from '../components/QuoteStep3'
import quoteProgressStyles from '../styles/QuoteProgress.module.css'
import {useContext} from 'react'
import {QuoteContext} from '../contexts/QuoteContext'
const quote = () => {
const {render, data} = useContext(QuoteContext)
const [step, setStep] = render
const [formValues, setFormValues] = data
return (
<div className={quoteProgressStyles.section}>
<div className={quoteProgressStyles.container}>
<div className={quoteProgressStyles.progressBar}>
<div className={`${quoteProgressStyles.step} ${step === 1 || step === 2 || step === 3 ? `${quoteProgressStyles.active}` : null}`} ><b>Step1</b>Requirement Information</div>
<div className={`${quoteProgressStyles.step} ${step === 2 || step === 3 ? `${quoteProgressStyles.active}` : null}`} ><b>Step2</b>Personal Information</div>
<div className={`${quoteProgressStyles.step} ${step === 3 ? `${quoteProgressStyles.active}` : null}`} ><b>Step3</b>Delivery Information</div>
</div>
<div>
{step === 1 ? <QuoteStep1 /> : null}
{step === 2 ? <QuoteStep2 /> : null}
{step === 3 ? <QuoteStep3 /> : null}
</div>
</div>
</div>
)
}
export default quote
这是第一步:
import { Formik, Form, useField } from 'formik'
import * as Yup from 'yup'
import QuoteStep1Styles from '../styles/QuoteStep1.module.css'
import {useContext} from 'react'
import {QuoteContext} from '../contexts/QuoteContext'
import MaskedInput from 'react-input-mask';
import {useEfeect} from 'react'
const QuoteStep1 = () => {
const {render, data} = useContext(QuoteContext)
const [step, setStep] = render
const [formValues, setFormValues] = data
const MyMaskedTextInput = ({ label, ...props }) => {
const [field, meta] = useField(props)
return (
<div className={QuoteStep1Styles.outerBox}>
<label htmlFor={props.id || props.name}>{label}</label>
<div className={QuoteStep1Styles.innerBox}>
<MaskedInput {...field} {...props} />
<label htmlFor={props.id || props.name}>Units</label>
</div>
</div>
)
}
return (
<div>
<Formik
initialValues={formValues}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2))
setSubmitting(false)
}, 400)
setStep(2)
}}
>
<Form className={QuoteStep1Styles.form}>
<div className={QuoteStep1Styles.SPR}>
<MyMaskedTextInput
label="SPR"
name="SPR"
mask="9999"
maskChar=" "
/>
</div>
<div className={QuoteStep1Styles.DFR}>
<MyMaskedTextInput
label="DFR"
name="DFR"
mask="9999"
maskChar=" "
/>
</div>
<div className={QuoteStep1Styles.ACR}>
<MyMaskedTextInput
label="ACR"
name="ACR"
mask="9999"
maskChar=" "
/>
</div>
<div className={QuoteStep1Styles.HWS}>
<MyMaskedTextInput
label="HWS"
name="HWS"
mask="9999"
maskChar=" "
/>
</div>
<button className={QuoteStep1Styles.button} type="submit">CONTINUE</button>
</Form>
</Formik>
</div>
)
}
export default QuoteStep1
这是第 2 步:
import { Formik, Form, useField } from 'formik'
import * as Yup from 'yup'
import MaskedInput from 'react-input-mask';
import QuoteStep2Styles from '../styles/QuoteStep2.module.css'
import {useContext} from 'react'
import {QuoteContext} from '../contexts/QuoteContext'
const QuoteStep2 = () => {
const {render, data} = useContext(QuoteContext)
const [step, setStep] = render
const [formValues, setFormValues] = data
const MyTextInput = ({ label, ...props }) => {
const [field, meta] = useField(props)
return (
<div className={QuoteStep2Styles.outerBox}>
<label className={QuoteStep2Styles.label} htmlFor={props.id || props.name}>{label}</label>
<div className={QuoteStep2Styles.innerBox}>
<input className={QuoteStep2Styles.input} {...field} {...props} />
{meta.touched && meta.error ? (
<div className={QuoteStep2Styles.error}>{meta.error}</div>
) : null}
</div>
</div>
)
}
const MyMaskedTextInput = ({ label, ...props }) => {
const [field, meta] = useField(props)
return (
<div className={QuoteStep2Styles.outerBox}>
<label className={QuoteStep2Styles.label} htmlFor={props.id || props.name}>{label}</label>
<div className={QuoteStep2Styles.innerBox}>
<MaskedInput className={QuoteStep2Styles.input} {...field} {...props} />
{meta.touched && meta.error ? (
<div className={QuoteStep2Styles.error}>{meta.error}</div>
) : null}
</div>
</div>
)
}
return (
<div>
<Formik
initialValues={formValues}
validationSchema={Yup.object({
fName: Yup.string()
.max(50, 'Must be 50 characters or less')
.required('Required'),
lName: Yup.string()
.max(50, 'Must be 50 characters or less')
.required('Required'),
cName: Yup.string()
.max(120, 'Must be 120 characters or less'),
email: Yup.string()
.email('Invalid email address')
.required('Required'),
phone: Yup.string()
.required('Required')
})}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2))
setSubmitting(false)
}, 400)
setStep(3)
}}
>
<div className={QuoteStep2Styles.section}>
<div className={QuoteStep2Styles.container}>
<Form className={QuoteStep2Styles.form}>
<div className={QuoteStep2Styles.fName}>
<MyTextInput
label="First Name"
name="fName"
type="text"
maxLength='50'
autoComplete="given-name"
placeholder="Jane"
/>
</div>
<div className={QuoteStep2Styles.lName}>
<MyTextInput
label="Last Name"
name="lName"
type="text"
maxLength='50'
autoComplete="family-name"
placeholder="Doe"
/>
</div>
<div className={QuoteStep2Styles.cName}>
<MyTextInput
label="Company Name"
name="cName"
type="text"
maxLength='120'
autoComplete="organization"
placeholder="Acme Widget, Inc"
/>
</div>
<div className={QuoteStep2Styles.email}>
<MyTextInput
label="Email Address"
name="email"
type="email"
autoComplete="email"
placeholder="[email protected]"
/>
</div>
<div className={QuoteStep2Styles.phone}>
<MyMaskedTextInput
label="Phone"
name="phone"
mask="(999) 999-9999"
autoComplete="tel-national"
placeholder="(000) 000-0000"
/>
</div>
<div className={`${QuoteStep2Styles.outerBox} ${QuoteStep2Styles.buttons}`}>
<button type="submit">CONTINUE</button>
<button onClick={() =>{setStep(1)}}>BACK</button>
</div>
</Form>
</div>
</div>
</Formik>
</div>
)
}
export default QuoteStep2
您可以在formik对象中设置enableReinitialize属性
示例: 启用重新初始化:true,
文档链接 https://formik.org/docs/api/withFormik#enablereinitialize-boolean
我遇到了同样的问题,最终使用zustand跨步骤管理表单状态。 您可以使用其他状态管理。
const handleNext = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
setFormValues(values) // this is save the values globally
};
您可以将状态清除为onSubmit()