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

react-hook-form表单校验:如何实现至少一个输入字段有值?

React Hook Form 实现「至少一个字段有值」的校验逻辑

要实现「只要至少一个输入字段有值,表单就有效」的校验,有两种常用方案,具体如下:

方案一:表单级全局校验

利用 useForm 的 validate 选项,在表单提交时统一检查所有目标字段是否全为空,若全为空则返回错误信息。

示例代码:

import { useForm, Controller } from 'react-hook-form';
import TextField from '@mui/material/TextField';

function App() {
  const { control, handleSubmit, formState: { errors } } = useForm({
    defaultValues: {
      value1: '',
      value2: '',
      value3: ''
    },
    validate: (data) => {
      const errors = {};
      // 检查所有字段是否都为空
      const allFieldsEmpty = Object.values(data).every(val => !val.trim());
      if (allFieldsEmpty) {
        // 可将错误绑定到任意字段,或多个字段
        errors.value1 = '至少需要填写一个字段';
      }
      return errors;
    }
  });

  const onSubmit = (data) => {
    console.log('提交的数据:', data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        control={control}
        name="value1"
        render={({ field }) => (
          <TextField
            {...field}
            fullWidth
            sx={{ maxWidth: 600, mb: 2 }}
            label="Value 1"
            margin="dense"
            error={!!errors.value1}
            helperText={errors.value1?.message}
          />
        )}
      />
      <Controller
        control={control}
        name="value2"
        render={({ field }) => (
          <TextField
            {...field}
            fullWidth
            sx={{ maxWidth: 600, mb: 2 }}
            label="Value 2"
            margin="dense"
          />
        )}
      />
      <Controller
        control={control}
        name="value3"
        render={({ field }) => (
          <TextField
            {...field}
            fullWidth
            sx={{ maxWidth: 600, mb: 2 }}
            label="Value 3"
            margin="dense"
          />
        )}
      />
      <button type="submit">提交表单</button>
    </form>
  );
}

export default App;

这种方案适合只需要在提交时做一次全局校验的场景,错误提示可以集中显示在某个字段或单独的提示区域。

方案二:字段级联动校验

通过 watch 监听所有目标字段的值,给每个字段添加自定义校验规则,实时检查是否有至少一个字段有值。

示例代码:

import { useForm, Controller } from 'react-hook-form';
import TextField from '@mui/material/TextField';

function App() {
  const { control, handleSubmit, formState: { errors }, watch } = useForm({
    defaultValues: {
      value1: '',
      value2: '',
      value3: ''
    }
  });

  // 监听需要校验的字段组
  const targetFields = watch(['value1', 'value2', 'value3']);

  const onSubmit = (data) => {
    console.log('提交的数据:', data);
  };

  // 自定义校验规则:只要有一个字段非空就通过
  const atLeastOneFilled = () => {
    const hasValidValue = targetFields.some(val => val.trim());
    return hasValidValue || '至少需要填写一个字段';
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        control={control}
        name="value1"
        rules={{ validate: atLeastOneFilled }}
        render={({ field }) => (
          <TextField
            {...field}
            fullWidth
            sx={{ maxWidth: 600, mb: 2 }}
            label="Value 1"
            margin="dense"
            error={!!errors.value1}
            helperText={errors.value1?.message}
          />
        )}
      />
      <Controller
        control={control}
        name="value2"
        rules={{ validate: atLeastOneFilled }}
        render={({ field }) => (
          <TextField
            {...field}
            fullWidth
            sx={{ maxWidth: 600, mb: 2 }}
            label="Value 2"
            margin="dense"
            error={!!errors.value2}
            helperText={errors.value2?.message}
          />
        )}
      />
      <Controller
        control={control}
        name="value3"
        rules={{ validate: atLeastOneFilled }}
        render={({ field }) => (
          <TextField
            {...field}
            fullWidth
            sx={{ maxWidth: 600, mb: 2 }}
            label="Value 3"
            margin="dense"
            error={!!errors.value3}
            helperText={errors.value3?.message}
          />
        )}
      />
      <button type="submit">提交表单</button>
    </form>
  );
}

export default App;

这种方案支持实时校验,用户输入时就能触发规则检查,适合需要即时反馈的场景。

额外优化建议

如果字段数量较多,可以将字段名存入数组,通过循环渲染 Controller 和 TextField,减少重复代码:

const fieldNames = ['value1', 'value2', 'value3'];

// 渲染部分
{fieldNames.map(name => (
  <Controller
    key={name}
    control={control}
    name={name}
    rules={{ validate: atLeastOneFilled }}
    render={({ field }) => (
      <TextField
        {...field}
        fullWidth
        sx={{ maxWidth: 600, mb: 2 }}
        label={name.charAt(0).toUpperCase() + name.slice(1)}
        margin="dense"
        error={!!errors[name]}
        helperText={errors[name]?.message}
      />
    )}
  />
))}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 12:50:20