next.js 为什么我在使用Formik提交表单后收到以下警告:某个组件正在将受控输入更改为不受控输入

w9apscun  于 2023-04-20  发布在  其他
关注(0)|答案(1)|浏览(110)

我在使用Formik提交表单时收到以下警告:组件正在将受控输入更改为不受控输入。这可能是由值从已定义更改为未定义引起的,而这种情况不应发生。请决定在组件的生命周期内使用受控输入元素还是不受控输入元素。
我知道关于这个警告有很多问题已经得到了回答,我也大致知道它的意思。但我就是不明白它发生在哪里,输入在哪里或什么时候变得不受控制。
我已经尝试删除handleRegister函数中的formik.resetForm()formik.setFieldValue(),因为我认为它们可能将输入设置为undefined,但它没有改变任何东西。
这是我的register组件的代码:

const Register: NextPage = () => {
  const { data: session, status } = useSession()
  if (session) {
    const router = useRouter()
    router.push('/')
  }

  const [error, setError] = useState('')
  const [success, setSuccess] = useState('')

  const handleRegister = async (values: RegisterInputsData) => {
    setError('')
    setSuccess('')

    const registerInputsData = {
      ...values
    }

    if (!registerInputsData.company.website) {
      delete registerInputsData.company.website
    }

    if (!registerInputsData.company.socials) {
      delete registerInputsData.company.socials
    }

    const registerInputsDataJSON = JSON.stringify(registerInputsData)

    const endpoint: RequestInfo = '/api/register'
    const options: RequestInit = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: registerInputsDataJSON
    }

    try {
      const response: Response = await fetch(endpoint, options)

      if (!response.ok) {
        const { error } = await response.json()
        if (typeof error === 'object' && error.name === 'ValidationError') {
          const formikError = yupToFormErrors(error)
          return formik.setErrors(formikError)
        }
        return setError(error)
      }
      formik.resetForm()
      setSuccess(registerInputsData.user.email)
    } catch (error) {
      setError('Register failed')
    } finally {
      formik.setFieldValue('user.password', formik.initialValues.user.password, false)
      formik.setFieldValue('user.passwordConfirmation', formik.initialValues.user.passwordConfirmation, false)
      formik.setFieldValue('user.pin', formik.initialValues.user.pin, false)
      formik.setFieldValue('user.pinConfirmation', formik.initialValues.user.pinConfirmation, false)
    }
  }

  const formik = useFormik({
    initialValues: {
      user: {
        email: '',
        password: '',
        passwordConfirmation: '',
        pin: '',
        pinConfirmation: ''
      },

      company: {
        name: '',
        title: '',
        firstName: '',
        lastName: '',
        street: '',
        houseNumber: '',
        postcode: '',
        city: '',
        country: '',
        countryCode: '',
        callNumber: '',
        email: '',
        website: '',
        socials: ''
      }
    },
    validationSchema: registerYupSchema,
    onSubmit: async (values) => {
      await handleRegister(values)
    }
  })

  return status === 'loading' ? <></> : (
    <>
      <Navbar />

      <form onSubmit={formik.handleSubmit} noValidate className={styles.form}>

        <div className={styles.section}>
          <h3 className={styles.h3}>User</h3>

          <div className={styles.group}>
            <input
              name='user.email'
              type='text'
              value={formik.values.user.email}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Email<span>*</span></label>
            {formik.touched.user?.email && formik.errors.user?.email && <div className={styles.error}>{formik.errors.user.email}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='user.password'
              type='password'
              value={formik.values.user.password}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Password<span>*</span></label>
            {formik.touched.user?.password && formik.errors.user?.password && <div className={styles.error}>{formik.errors.user.password}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='user.passwordConfirmation'
              type='password'
              value={formik.values.user.passwordConfirmation}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Password Confirmation<span>*</span></label>
            {formik.touched.user?.passwordConfirmation && formik.errors.user?.passwordConfirmation && <div className={styles.error}>{formik.errors.user.passwordConfirmation}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='user.pin'
              type='password'
              value={formik.values.user.pin}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Pin<span>*</span></label>
            {formik.touched.user?.pin && formik.errors.user?.pin && <div className={styles.error}>{formik.errors.user.pin}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='user.pinConfirmation'
              type='password'
              value={formik.values.user.pinConfirmation}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Pin Confirmation<span>*</span></label>
            {formik.touched.user?.pinConfirmation && formik.errors.user?.pinConfirmation && <div className={styles.error}>{formik.errors.user.pinConfirmation}</div>}
          </div>
        </div>

        <div className={styles.section}>
          <h3 className={styles.h3}>Company</h3>

          <div className={styles.group}>
            <input
              name='company.name'
              type='text'
              value={formik.values.company.name}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Company Name<span>*</span></label>
            {formik.touched.company?.name && formik.errors.company?.name && <div className={styles.error}>{formik.errors.company.name}</div>}
          </div>

          <div className={styles.group}>
            <select
              name='company.title'
              value={formik.values.company.title}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.select}
              aria-label='Title'
            >
              <option value='' hidden className={styles.option}></option>
              <option value='Ms.' className={styles.option}>Ms.</option>
              <option value='Mr.' className={styles.option}>Mr.</option>
            </select>
            <label className={styles.label}>Title<span>*</span></label>
            {formik.touched.company?.title && formik.errors.company?.title && <div className={styles.error}>{formik.errors.company.title}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.firstName'
              type='text'
              value={formik.values.company.firstName}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>First Name<span>*</span></label>
            {formik.touched.company?.firstName && formik.errors.company?.firstName && <div className={styles.error}>{formik.errors.company.firstName}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.lastName'
              type='text'
              value={formik.values.company.lastName}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Last Name<span>*</span></label>
            {formik.touched.company?.lastName && formik.errors.company?.lastName && <div className={styles.error}>{formik.errors.company.lastName}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.street'
              type='text'
              value={formik.values.company.street}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Street<span>*</span></label>
            {formik.touched.company?.street && formik.errors.company?.street && <div className={styles.error}>{formik.errors.company.street}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.houseNumber'
              type='text'
              value={formik.values.company.houseNumber}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>House Number<span>*</span></label>
            {formik.touched.company?.houseNumber && formik.errors.company?.houseNumber && <div className={styles.error}>{formik.errors.company.houseNumber}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.postcode'
              type='text'
              value={formik.values.company.postcode}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Postcode<span>*</span></label>
            {formik.touched.company?.postcode && formik.errors.company?.postcode && <div className={styles.error}>{formik.errors.company.postcode}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.city'
              type='text'
              value={formik.values.company.city}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>City<span>*</span></label>
            {formik.touched.company?.city && formik.errors.company?.city && <div className={styles.error}>{formik.errors.company.city}</div>}
          </div>

          <div className={styles.group}>
            <select
              name='company.country'
              value={formik.values.company.country}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.select}
              aria-label='Country'
            >
              <option value='' hidden className={styles.option}></option>
              {Object.keys(countries).map((key, i) => (
                <option value={countries[key].name} key={i} className={styles.option}>{countries[key].name}</option>
              ))}
            </select>
            <label className={styles.label}>Country<span>*</span></label>
            {formik.touched.company?.country && formik.errors.company?.country && <div className={styles.error}>{formik.errors.company.country}</div>}
          </div>

          <div className={styles.group}>
            <select
              name='company.countryCode'
              value={formik.values.company.countryCode}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.select}
              aria-label='Country Code'
            >
              <option value='' hidden className={styles.option}></option>
              {Object.keys(countries).map((key, i) => (
                <option value={'+' + countries[key].phone} key={i} className={styles.option}>{countries[key].emoji + ' +' + countries[key].phone}</option>
              ))}
            </select>
            <label className={styles.label}>Country Code<span>*</span></label>
            {formik.touched.company?.countryCode && formik.errors.company?.countryCode && <div className={styles.error}>{formik.errors.company.countryCode}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.callNumber'
              type='text'
              value={formik.values.company.callNumber}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Call Number<span>*</span></label>
            {formik.touched.company?.callNumber && formik.errors.company?.callNumber && <div className={styles.error}>{formik.errors.company.callNumber}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.email'
              type='text'
              value={formik.values.company.email}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Email<span>*</span></label>
            {formik.touched.company?.email && formik.errors.company?.email && <div className={styles.error}>{formik.errors.company.email}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.website'
              type='text'
              value={formik.values.company.website}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Website</label>
            {formik.touched.company?.website && formik.errors.company?.website && <div className={styles.error}>{formik.errors.company.website}</div>}
          </div>

          <div className={styles.group}>
            <input
              name='company.socials'
              type='text'
              value={formik.values.company.socials}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              className={styles.input}
            />
            <label className={styles.label}>Socials</label>
            {formik.touched.company?.socials && formik.errors.company?.socials && <div className={styles.error}>{formik.errors.company.socials}</div>}
          </div>
        </div>

        <button type='submit' disabled={formik.isSubmitting} className={styles.button}>Register</button>
      </form>

      {formik.isSubmitting && <div className={styles.lds_ring}><div></div><div></div><div></div><div></div></div>}
      {!formik.isSubmitting && error && <div className={styles.message}>{error}</div>}
      {!formik.isSubmitting && success && <div className={styles.message}>Registration successful - A verification email has been sent to the following email: {success}</div>}
    </>
  )
}

export default Register

我很感激我能得到的任何帮助。

3ks5zfa0

3ks5zfa01#

在这种情况下,values参数是对一个对象的直接引用。尽管你使用了spread操作符来创建它的深层副本,但由于值中有嵌套的对象,你也需要对这些对象使用spread操作符。否则它们将是浅层副本。
当你删除他们的属性(网站,社交),如果尊重的输入仍然是空的,输入变得不受控制。
解决方案可能如下所示:

const registerInputsData = {
   user: {...values.user},
   company: {...values.company}
}

相关问题