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

Posted

技术标签:

【中文标题】防止多步 Formik 表单在重新渲染上一步时重置表单控件输入【英文标题】:Prevent a multi step Formik form from resetting the form control inputs on re-rendering of the previous step 【发布时间】:2021-07-22 07:18:39 【问题描述】:

我正在尝试使用 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="jane@email.com"
                />
            </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

【问题讨论】:

【参考方案1】:

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

示例: enableReinitialize: true,

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

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。

以上是关于防止多步 Formik 表单在重新渲染上一步时重置表单控件输入的主要内容,如果未能解决你的问题,请参考以下文章

Formik - 确认后如何重置表格

如何在reactjs中重置表单和登录错误消息

防止提交路线更改 Formik AutoSave

Formik 在空字段上也显示错误

多词干jquery表单不起作用

使用 Formik 的 React-Native 选择器