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

React Native中React Hook Form搭配Yup校验不生效及用法咨询

问题排查&解决

你的yup校验不生效是代码里的几个错误导致的,修复后即可正常运行:

  1. 第一个邮箱输入框的Controller的name属性写的是大写开头的Email,和yup schema里定义的小写email字段名不匹配,yup找不到对应字段自然不会触发校验
  2. 不需要在useEffect里手动调用register注册字段,Controller组件会自动帮你完成字段注册,重复注册会导致逻辑冲突
  3. 密码、确认密码输入框的Controller里没有用field返回的onChange、onBlur方法,自己手动写setValue会丢失失焦触发校验的能力,也不符合组件的设计规范
  4. 提交函数enviar里打印的变量名写错了,参数是dados,你写的data会报错

疑问解答

1. yup是react-hook-form的必选项吗?

不是。react-hook-form本身自带轻量的校验能力,就是你写在Controller的rules属性里的规则,完全可以满足简单的校验需求。只有当你需要处理复杂校验逻辑(比如跨字段联动校验、统一管理全局校验规则、自动TS类型推导、更复杂的格式校验)的时候,才需要搭配yup/zod这类schema校验库使用。

2. yup和react-hook-form搭配的正确使用步骤

你已经走对了大部分流程,只要注意这几点即可:

  • 定义yup schema的时候,字段名必须和Controller的name属性完全一致,大小写也要对应
  • 在useForm的配置项里传入resolver: yupResolver(你的schema)即可,不需要额外做其他配置
  • 校验错误会统一挂载在formState.errors下,key就是你定义的字段名,错误提示就是yup里写的提示内容

3. Controller的rules属性怎么定义

rules是react-hook-form内置的校验配置项,常见的配置如下:

rules={{
  // 必填校验,值为字符串的话就是错误提示
  required: "邮箱不能为空",
  // 字符串最小/最大长度
  minLength: {value: 8, message: "密码最少8位"},
  maxLength: {value: 20, message: "密码最多20位"},
  // 数字的最小/最大值
  min: {value: 18, message: "年龄不能小于18岁"},
  // 正则校验
  pattern: {value: /^1[3-9]\d{9}$/, message: "请输入正确的手机号"},
  // 自定义校验函数,返回true就是校验通过,返回字符串就是错误提示
  validate: value => value === 密码字段的值 || "两次输入的密码不一致"
}}

如果同时配置了yup resolver和rules属性,两类规则都会生效,rules的校验优先级更高,任意规则不通过都会返回错误。


修正后的完整代码

import React from "react";
import {
  View,
  TextInput,
  TouchableOpacity,
  Text,
  StyleSheet,
} from "react-native";
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

const schema = yup.object({
  email: yup.string().email("请输入正确的邮箱格式").required("邮箱不能为空"),
  senha: yup
    .string()
    .min(8, "密码最少需要8位字符"),
  confirmacaoSenha: yup
    .string()
    .oneOf([yup.ref('senha'), null], "两次输入的密码不一致")
});

const AcessoFormulario = ({ tipoUsuario }) => {
  const {
    control,
    handleSubmit,
    formState: { errors },
  } = useForm({
    resolver: yupResolver(schema),
    defaultValues: {
      email: "",
      senha: "",
      confirmacaoSenha: "",
    },
  });

  const enviar = (dados) => {
    console.log(dados);
    //TODO firebase auth
  };

  return (
    <View style={styles.container}>
      <View style={styles.subContainer}>
        <Text style={styles.label}>E-mail:</Text>
        <Controller
          control={control}
          render={({ field: { onChange, onBlur, value } }) => (
            <TextInput
              style={styles.input}
              onBlur={onBlur}
              onChangeText={onChange}
              value={value}
              keyboardType="email-address"
              autoCapitalize="none"
            />
          )}
          name="email"
        />
        {errors.email && <Text>{errors.email.message}</Text>}
      </View>
      <View style={styles.subContainer}>
        <Text style={styles.label}>Senha:</Text>
        <Controller
          control={control}
          render={({ field: { onChange, onBlur, value } }) => (
            <TextInput
              style={styles.input}
              onBlur={onBlur}
              onChangeText={onChange}
              value={value}
              secureTextEntry
            />
          )}
          name="senha"
        />
        {errors.senha && <Text>{errors.senha.message}</Text>}
      </View>
      <View style={styles.subContainer}>
        <Text style={styles.label}>Confirmação de senha:</Text>
        <Controller
          control={control}
          render={({ field: { onChange, onBlur, value } }) => (
            <TextInput
              style={styles.input}
              onBlur={onBlur}
              onChangeText={onChange}
              value={value}
              secureTextEntry
            />
          )}
          name="confirmacaoSenha"
        />
        {errors.confirmacaoSenha && <Text>{errors.confirmacaoSenha.message}</Text>}
      </View>

      <TouchableOpacity style={styles.btnEnviar} onPress={handleSubmit(enviar)}>
        <Text style={styles.btnTexto}>Registrar-se</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    display: "flex",
    flexDirection: "column",
    marginTop: 40,
    margin: 10,
    padding: 10,
    backgroundColor: "#77d477",
    borderRadius: 20,
  },
  input: {
    borderWidth: 2,
    borderColor: "#ffffff",
    borderRadius: 6,
    margin: 2,
    paddingHorizontal: 8,
    paddingVertical: 4
  },
  label: {
    color: "#ffffff",
    fontWeight: "bold",
    fontSize: 15,
    marginBottom: 4
  },
  subContainer: {
    margin: 15,
  },
  btnEnviar: {
    backgroundColor: "#ffffff",
    margin: 15,
    padding: 10,
    borderRadius: 6
  },
  btnTexto: {
    color: "#77d477",
    textAlign: "center",
    fontWeight: "bold",
    fontSize: 20,
  },
});

export default AcessoFormulario;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 01:54:02