You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Formik的useField hook验证Select组件报错如何解决

问题根源

两个核心错误导致你的代码无法运行:

  1. useField 是依赖Formik上下文的Hook,你当前将它写在了<Formik>组件的外部作用域,Formik上下文未初始化,所以抛出getFieldProps undefined的报错。
  2. useField返回值结构为[field, meta, helpers],你错误地把第一个返回值field当作了helpers使用,同时传参写法不符合新版Formik规范,也出现了变量未定义的问题。

修复步骤

  • 移动useField的调用位置到<Formik>的回调作用域内,保证能访问到Formik上下文
  • 修正useField的传参和返回值解构,新版Formik直接传入字段名字符串即可,不需要传对象
  • 删除重复的赋值逻辑,匹配Yup校验规则传递正确的字段值类型
  • 补充错误提示展示逻辑

修复后完整代码

import React from 'react';
import * as Yup from 'yup';
import PropTypes from 'prop-types';
import { Formik, useField } from 'formik';
import {
  Box,
  Button,
  FormHelperText,
  TextField,
  makeStyles,
  Grid
} from '@material-ui/core';
import { useHistory } from 'react-router-dom';
import countries from '../../profile/candidate/ProfileCreateView/PersonalInfo/countries';
import Select from 'react-select';

const useStyles = makeStyles(theme => ({}));

const StepTwo = ({
  className,
  formValues,
  handleNextStep,
  handleChangeOnParent,
  ...rest
}) => {
  const classes = useStyles();

  const onSubmitHandler = async (
    values,
    { resetForm, setErrors, setStatus, setSubmitting }
  ) => {
    try {
      const {
        country: { text: country },
      } = values;
      handleNextStep(2, {
        country,
      });
    } catch (err) {
      console.error(err);
      setStatus({ success: false });
      setErrors({ submit: err.message });
      setSubmitting(false);
    }
  };

  // 抽离Select组件,在内部调用useField
  const CountrySelect = () => {
    // 正确写法:传字段名字符串,解构出三个返回值
    const [field, meta, helpers] = useField("country");
    const { setValue, setTouched } = helpers;

    return (
      <>
        <Select
          styles={customStyles}
          placeholder="Country"
          name={field.name}
          value={field.value}
          options={countries}
          getOptionLabel={option => option.text}
          onChange={option => {
            // Yup要求country是对象,直接传整个option,不要只传option.value
            setValue(option);
            setTouched(true);
            handleChangeOnParent('country', option);
          }}
        />
        {/* 展示校验错误 */}
        {meta.touched && meta.error && (
          <FormHelperText error>{meta.error}</FormHelperText>
        )}
      </>
    )
  }

  return (
    <Formik
      initialValues={{
        country: formValues.country || null,
      }}
      validationSchema={Yup.object().shape({
        country: Yup.object().required('Country is required'),
      })}
      onSubmit={onSubmitHandler}
      enableReinitialize
    >
      {({
        handleSubmit,
        isSubmitting
      }) => (
        <form onSubmit={handleSubmit}>
          <Grid container spacing={3}>
            <Grid item xs={12}>
              {/* 直接使用抽离的CountrySelect组件 */}
              <CountrySelect />
            </Grid>
          </Grid>
          {/* 提交按钮可根据需求调整 */}
          <Box mt={3}>
            <Button
              disabled={isSubmitting}
              fullWidth
              type="submit"
              variant="contained"
              color="primary"
            >
              下一步
            </Button>
          </Box>
        </form>
      )}
    </Formik>
  );
};

StepTwo.propTypes = {
  className: PropTypes.string
};

export default StepTwo;

额外说明

  • 如果你不想单独抽离组件,也可以直接在Formik的回调里调用useField,只要保证调用位置处于Formik组件包裹的内部即可
  • 之前你传useField({name: country})时没给country加引号,会被识别为未定义的变量,要传对象参数需要写useField({name: "country"}),不过新版Formik优先推荐直接传字符串参数的写法
  • 你之前的initialValues里country默认值是空字符串,和Yup要求的对象类型不匹配,已经改成了null,避免初始化时报类型错误

内容的提问来源于stack exchange,提问作者emyy96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 07:21:02