防止多步骤 Formik 表单在重新渲染上一步时重置表单控件输入

问题描述 投票:0回答:2

我正在尝试使用 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
reactjs forms next.js state formik
2个回答
0
投票

您可以在formik对象中设置enableReinitialize属性

示例: 启用重新初始化:true,

文档链接 https://formik.org/docs/api/withFormik#enablereinitialize-boolean


0
投票

我遇到了同样的问题,最终使用zustand跨步骤管理表单状态。 您可以使用其他状态管理。

const handleNext = () => {
    setActiveStep((prevActiveStep) => prevActiveStep + 1);
    setFormValues(values) // this is save the values globally 
};

您可以将状态清除为onSubmit()


    

© www.soinside.com 2019 - 2024. All rights reserved.