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。」

相关推荐
特立独行的猫a1 小时前
C 语言各种指针详解
java·c语言·开发语言
彭于晏Yan2 小时前
MyBatis-Plus使用动态表名分表查询
java·开发语言·mybatis
李鸿耀3 小时前
主题换肤指南:设计到开发的完整实践
前端
MediaTea7 小时前
Python IDE:Spyder
开发语言·ide·python
不枯石8 小时前
Matlab通过GUI实现点云的均值滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab·均值算法
不枯石8 小时前
Matlab通过GUI实现点云的双边(Bilateral)滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab
带娃的IT创业者8 小时前
TypeScript + React + Ant Design 前端架构入门:搭建一个 Flask 个人博客前端
前端·react.js·typescript
二十雨辰8 小时前
vite如何处理项目中的资源
开发语言·javascript
聆风吟º9 小时前
远程录制新体验:Bililive-go与cpolar的无缝协作
开发语言·后端·golang
非凡ghost9 小时前
MPC-BE视频播放器(强大视频播放器) 中文绿色版
前端·windows·音视频·软件需求