React From表单使用Formik和yup进行校验

一、Formik的使用

官方文档地址:https://formik.org/docs/tutorial#validation

  1. 首先安装依赖
TypeScript 复制代码
yarn add  formik

2.导入并初始化

TypeScript 复制代码
import { useFormik } from 'formik';
initialValues:初始化 输入框的密码和账号 
onSubmit:当点击提交按钮时,调用这个钩子,拿到输入框的vaule值

3.打印一下formik看一下都有哪些钩子

TypeScript 复制代码
 const formik = useFormik({
        initialValues: {
            mobile: '',
            code: ''
        },
        validate,
        onSubmit: values => {
            // 拿到输入框的值
            console.log(values);
        },
    });
    console.log(formik);

4.在form表单中绑定这些钩子会自动调用

5.formik里提供了校验规则,但是还是要自己手动写一下

6.进行校验结果控制

TypeScript 复制代码
{formik.touched.mobile && formik.errors.mobile ? < div className='validate'>{formik.errors.mobile}</div> : null}

完整使用

TypeScript 复制代码
import React from 'react'
import NavBar from '../NavBar/NavBar'
import style from './Login.module.scss'
import Input from '../Input/input.js'
// 导入表单验证的formik
import { useFormik } from 'formik';
//导入校验验证规则yup
//import * as yup from 'yup';
const validate = values => {
    const error = {}
    if (!values.mobile) {
        error.mobile = '手机号不能为空'
    }
    if (!values.code) {
        error.code = '验证码不能为空'
    }
    return error
}
export default function Login() {
    const formik = useFormik({
        initialValues: {
            mobile: '',
            code: ''
        },
        validate,
        onSubmit: values => {
            // 拿到输入框的值
            console.log(values);
        },
    });
    console.log(formik);
    return (
        <div className={style.root}>
            <NavBar>登录</NavBar>
            <div className='content'>
                <h3>短信登录</h3>
                <form onSubmit={formik.handleSubmit}>
                    <div className='input-item'>
                        <Input
                            name='mobile'
                            placeholder='请输入手机号'
                            value={formik.values.mobile}
                            onChange={formik.handleChange}
                            onBlur={formik.handleBlur}
                        />
                        {formik.touched.mobile && formik.errors.mobile ? < div className='validate'>{formik.errors.mobile}</div> : null}
 
                        <div className='input-item'>
                            <Input
                                placeholder='请输入验证码'
                                extra='获取验证码'
                                name='code'
                                onChange={formik.handleChange}
                                onBlur={formik.handleBlur}
                                value={formik.values.code} />
                            {formik.touched.code && formik.errorscode ? <div className='validate'>{formik.errors.code}</div> : null}
                        </div>
                        <button type='submit' className='login-btn'>登录</button>
                    </div>
                </form>
            </div >
        </div >
    )
}

二、使用yup进行校验

第一部分的校验看起来不是很方便,但是如果使用yup进行校验的话会比较方便一些

yup文档:https://www.npmjs.com/package/yup

三、实战过程及讲解

|-------------|---------------------------|
| 工具 | 职责 |
| Formik | 表单状态管家(值、错误、是否通过) |
| Yup | 校验规则书写器(字段必须满足什么条件) |
| useValldate | 自定义钩子,把错误信息转换为formik能用的格式 |

  1. 把validate函数注册给formik函数
TypeScript 复制代码
<Formik validate={validate} ... />
TypeScript 复制代码
validate(currentFormValues)   // 当前整个表单值
TypeScript 复制代码
import { useCallback, useMemo } from 'react';
import { catchYupError } from '@tencent/dboss-module-utility/common/utils/yup/catchYupError';
import * as Yup from 'yup';
import { set } from 'lodash';
import { t } from '@i18n';
import { validationSchema as backupStorageValidationSchema } from '@tencent/dboss-module-dbs/components/BackupStorageConfigForm';
import { StepId } from '../constants';
import { CrossClusterRollbackFormValues } from '../types';

const baseValidationSchemaMap = {
  sourceInstanceInfo: Yup.object({
    SourceInstanceId: Yup.string().required(t('该项为必填项')),
    StorageConfig: backupStorageValidationSchema({ allNotRequired: false }),
  }),
  // 其他步骤的校验逻辑
};

export const useValidate = (stepId: StepId) => {
  const validationSchema = useMemo(() => {
    const schema = baseValidationSchemaMap[stepId];

    if (typeof schema === 'function') {
      return schema();
    }
    return schema;
  }, [stepId]);

  const formValidator = useCallback(
    (formData: CrossClusterRollbackFormValues) => {
      const errors = {};
      if (validationSchema) {
        const schemaErrors = catchYupError(formData, validationSchema) ?? [];
        schemaErrors.forEach(({ path, message }) => {
          path && set(errors, path, message);
        });
      }
      switch (stepId) {
        case 'sourceInstanceInfo':
          // 移除这部分代码,因为 StorageConfig 的校验已经在 baseValidationSchemaMap 中处理了
          break;
        case 'rollbackBasicSettings':
          catchYupError(
            formData,
            Yup.object({
              PhysicalRollbackConfig: Yup.object({
                RollbackTime: Yup.string().required(t('该项为必填项')),
              }),
            }),
          ).forEach(({ path, message }) => {
            path && set(errors, path, message);
          });
          break;
        case 'targetInstanceSettings':
          catchYupError(
            formData,
            Yup.object({
              InstanceName: Yup.string().required(t('该项为必填项')),
            }),
          ).forEach(({ path, message }) => {
            path && set(errors, path, message);
          });
          break;
        case 'confirmation':
          break;
      }
      return errors;
    },
    [stepId, validationSchema],
  );

  return formValidator;
};

|------------------------|-------------------------------------|
| 步骤 | 规则(yup对象) |
| SourceInstanceInfo | SourceInstanceInfo+StorageConfig |
| rollbackBasicSettings | PhysicalRollbackConfig.RollbackTime |
| targetInstanceSettings | InstanceName |

4.执行yup校验(以sourceInstanceInfo为例子)

TypeScript 复制代码
Yup.object({
  SourceInstanceId: Yup.string().required('该项为必填项'),
  StorageConfig: backupStorageValidationSchema({ allNotRequired: false }),
})

backupstoragevaldationSchema会生成:

TypeScript 复制代码
Yup.object({
  BackupDir: Yup.string().required('该项为必填项'),
  Bucket: Yup.string().required('该项为必填项'),
  L5ServerName: Yup.string().required('该项为必填项'),
  Endpoint: Yup.string().required('该项为必填项'),
  AK: Yup.string().required('该项为必填项'),
  SK: Yup.string().required('该项为必填项'),
});

5.catchYupError会将错误信息转换为数组

TypeScript 复制代码
[
  { path: 'SourceInstanceId', message: '该项为必填项' },
  { path: 'StorageConfig.BackupDir', message: '该项为必填项' },
  { path: 'StorageConfig.Bucket', message: '该项为必填项' },
  ...
]

6.组装成Formik可以用的errors对象

TypeScript 复制代码
{
  SourceInstanceId: '该项为必填项',
  StorageConfig: {
    BackupDir: '该项为必填项',
    Bucket: '该项为必填项',
    ...
  }
}

7.formik收到errors

  • 如果 空对象 → 校验通过,立即执行 onSubmit
  • 如果 有字段 → 校验失败,阻断提交 ,并在对应 <InputField> 下显示红色提示

四、常见踩坑

  1. 字段路径写错
    例如把 StorageConfig.Bucket 写成 Bucket → Yup 找不到字段,永远通过。
  2. initialValues 缺字段
    StorageType → Yup 认为它是 undefined,不会触发 required()
  3. allNotRequired: true 传错
    传了 true → Yup 内部 .required(),永远通过。
  4. catchYupError 返回空数组
    说明 Yup 侧已经通过 ,问题一定在 路径或初始值

一句话总结:
「Formik 负责喊『校验!』,Yup 负责喊『哪里错了!』,useValidate 负责把错误翻译成 Formik 能看懂的地图,地图为空就放行 onSubmit。」

相关推荐
xiaowu0803 分钟前
IEnumerable、IEnumerator接口与yield return关键字的相关知识
java·开发语言·算法
csbysj20207 分钟前
Perl 目录操作指南
开发语言
-To be number.wan8 分钟前
C++ 运算符重载入门:让“+”也能为自定义类型服务!
开发语言·c++
未来之窗软件服务8 分钟前
幽冥大陆(七十九)Python 水果识别训练视频识别 —东方仙盟练气期
开发语言·人工智能·python·水果识别·仙盟创梦ide·东方仙盟
王家视频教程图书馆14 分钟前
android java 开发网路请求库那个好用请列一个排行榜
android·java·开发语言
POLITE322 分钟前
Leetcode 238.除了自身以外数组的乘积 JavaScript (Day 7)
前端·javascript·leetcode
光影少年27 分钟前
AI前端开发需要会哪些及未来发展?
前端·人工智能·前端框架
小宇的天下29 分钟前
Calibre Introduction to Calibre 3DSTACK(1)
开发语言
Vincent_Vang38 分钟前
多态 、抽象类、抽象类和具体类的区别、抽象方法和具体方法的区别 以及 重载和重写的相同和不同之处
java·开发语言·前端·ide
qualifying39 分钟前
JavaEE——多线程(3)
java·开发语言·java-ee