react之form表单工具:formik+yup

从网上搜到的form表单解决方案如下:

1.uform,地址:https://uformjs.org/#/MpI2Ij/dNFzFyTb

UForm 和核心特性:

  • 基于标准 JSON Schema 协议,数据化构建表单
  • 基于 rxjs 对表单内部的副作用做统一管理,轻松解决各种复杂联动校验场景
  • 支持各种表单布局方案
  • 支持可视化构建表单
  • 支持自定义组件扩展
  • 分布式状态管理,表单性能更高

不足:基于styled-components来开发的,涉及到的自定义样式主要是Form和FormItem层面上的样式。

样式很难hack,很难自定义。

2.react-jsonschema-form,地址:https://github.com/rjsf-team/react-jsonschema-form

  • 强耦合 Bootstrap,不方便扩展
  • JSON 描述不能很好的在 JSX 中描述
  • 没能很好的解决表单布局,表单联动的各种复杂问题
  • 性能不行,内部数据管理走的 React 的全量 rerender 机制来做数据同步

最终使用:Formik+yup组合来处理表单。github上star数目最多。

formik地址:https://github.com/jaredpalmer/formik

yup地址:https://github.com/jquense/yup

使用实例:

a. 不与yup结合,只使用formik,form表单代码如下:

import React from ‘react‘;
import { useFormik } from ‘formik‘;

const validate = values => {
  const errors = {};
  if (!values.firstName) {
    errors.firstName = ‘Required‘;
  } else if (values.firstName.length > 15) {
    errors.firstName = ‘Must be 15 characters or less‘;
  }

  if (!values.lastName) {
    errors.lastName = ‘Required‘;
  } else if (values.lastName.length > 20) {
    errors.lastName = ‘Must be 20 characters or less‘;
  }

  if (!values.email) {
    errors.email = ‘Required‘;
  } else if (!/^[A-Z0-9._%+-][email protected][A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
    errors.email = ‘Invalid email address‘;
  }

  return errors;
};

const SignupForm = () => {
  const formik = useFormik({
    initialValues: {
      firstName: ‘‘,
      lastName: ‘‘,
      email: ‘‘,
    },
    validate,
    onSubmit: values => {
      alert(JSON.stringify(values, null, 2));
    },
  });
  return (
    <form onSubmit={formik.handleSubmit}>
      <label htmlFor="firstName">First Name</label>
      <input
        id="firstName"
        name="firstName"
        type="text"
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
        value={formik.values.firstName}
      />
      {formik.touched.firstName && formik.errors.firstName ? (
        <div>{formik.errors.firstName}</div>
      ) : null}
      <label htmlFor="lastName">Last Name</label>
      <input
        id="lastName"
        name="lastName"
        type="text"
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
        value={formik.values.lastName}
      />
      {formik.touched.lastName && formik.errors.lastName ? (
        <div>{formik.errors.lastName}</div>
      ) : null}
      <label htmlFor="email">Email Address</label>
      <input
        id="email"
        name="email"
        type="email"
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
        value={formik.values.email}
      />
      {formik.touched.email && formik.errors.email ? (
        <div>{formik.errors.email}</div>
      ) : null}
      <button type="submit">Submit</button>
    </form>
  );
};

以上代码也是非常冗余。form表单校验全靠手动维护,很不方便。接下来

b.与yup结合。formik暴露了配置validationSchema与yup结合。示例如下

import React from ‘react‘;
import { useFormik } from ‘formik‘;
import * as Yup from ‘yup‘;

const SignupForm = () => {
  const formik = useFormik({
    initialValues: {
      firstName: ‘‘,
      lastName: ‘‘,
      email: ‘‘,
    },
    validationSchema: Yup.object({
      firstName: Yup.string()
        .max(15, ‘Must be 15 characters or less‘)
        .required(‘Required‘),
      lastName: Yup.string()
        .max(20, ‘Must be 20 characters or less‘)
        .required(‘Required‘),
      email: Yup.string()
        .email(‘Invalid email address‘)
        .required(‘Required‘),
    }),
    onSubmit: values => {
      alert(JSON.stringify(values, null, 2));
    },
  });
  return (
    <form onSubmit={formik.handleSubmit}>
      <label htmlFor="firstName">First Name</label>
      <input
        id="firstName"
        name="firstName"
        type="text"
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
        value={formik.values.firstName}
      />
      {formik.touched.firstName && formik.errors.firstName ? (
        <div>{formik.errors.firstName}</div>
      ) : null}
      <label htmlFor="lastName">Last Name</label>
      <input
        id="lastName"
        name="lastName"
        type="text"
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
        value={formik.values.lastName}
      />
      {formik.touched.lastName && formik.errors.lastName ? (
        <div>{formik.errors.lastName}</div>
      ) : null}
      <label htmlFor="email">Email Address</label>
      <input
        id="email"
        name="email"
        type="email"
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
        value={formik.values.email}
      />
      {formik.touched.email && formik.errors.email ? (
        <div>{formik.errors.email}</div>
      ) : null}
      <button type="submit">Submit</button>
    </form>
  );
};

如上,dom节点处的代码依然是比较复杂和重复的。

c.formik提供了一个Field组件

import React from ‘react‘;
import { Formik, Field, Form, ErrorMessage } from ‘formik‘;
import * as Yup from ‘yup‘;

const SignupForm = () => {
  return (
    <Formik
      initialValues={{ firstName: ‘‘, lastName: ‘‘, email: ‘‘ }}
      validationSchema={Yup.object({
        firstName: Yup.string()
          .max(15, ‘Must be 15 characters or less‘)
          .required(‘Required‘),
        lastName: Yup.string()
          .max(20, ‘Must be 20 characters or less‘)
          .required(‘Required‘),
        email: Yup.string()
          .email(‘Invalid email address‘)
          .required(‘Required‘),
      })}
      onSubmit={(values, { setSubmitting }) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          setSubmitting(false);
        }, 400);
      }}
    >
      <Form>
        <label htmlFor="firstName">First Name</label>
        <Field name="firstName" type="text" />
        <ErrorMessage name="firstName" />
        <label htmlFor="lastName">Last Name</label>
        <Field name="lastName" type="text" />
        <ErrorMessage name="lastName" />
        <label htmlFor="email">Email Address</label>
        <Field name="email" type="email" />
        <ErrorMessage name="email" />
        <button type="submit">Submit</button>
      </Form>
    </Formik>
  );
};

Field组件默认渲染为input。

<Field name="message" as="textarea"  className="form-input"/>

// <select className="my-select"/>
<Field name="colors" as="select" className="my-select">
  <option value="red">Red</option>
  <option value="green">Green</option>
  <option value="blue">Blue</option>
</Field>

最后,再进一步用法:

import React from ‘react‘;
import ReactDOM from ‘react-dom‘;
import { Formik, Form, useField } from ‘formik‘;
import styled from ‘@emotion/styled‘;
import * as Yup from ‘yup‘;

const MyTextInput = ({ label, ...props }) => {
  // useField() returns [formik.getFieldProps(), formik.getFieldMeta()]
  // which we can spread on <input> and also replace ErrorMessage entirely.
  const [field, meta] = useField(props);
  return (
    <>
      <label htmlFor={props.id || props.name}>{label}</label>
      <input className="text-input" {...field} {...props} />
      {meta.touched && meta.error ? (
        <div className="error">{meta.error}</div>
      ) : null}
    </>
  );
};

const MyCheckbox = ({ children, ...props }) => {
  // We need to tell useField what type of input this is
  // since React treats radios and checkboxes differently
  // than inputs/select/textarea.
  const [field, meta] = useField({ ...props, type: ‘checkbox‘ });
  return (
    <>
      <label className="checkbox">
        <input type="checkbox" {...field} {...props} />
        {children}
      </label>
      {meta.touched && meta.error ? (
        <div className="error">{meta.error}</div>
      ) : null}
    </>
  );
};

// Styled components ....
const StyledSelect = styled.select`
  /** ... * /
`;

const StyledErrorMessage = styled.div`
  /** ... * /
`;

const StyledLabel = styled.label`
 /** ...* /
`;

const MySelect = ({ label, ...props }) => {
  const [field, meta] = useField(props);
  return (
    <>
      <StyledLabel htmlFor={props.id || props.name}>{label}</StyledLabel>
      <StyledSelect {...field} {...props} />
      {meta.touched && meta.error ? (
        <StyledErrorMessage>{meta.error}</StyledErrorMessage>
      ) : null}
    </>
  );
};

// And now we can use these
const SignupForm = () => {
  return (
    <>
      <h1>Subscribe!</h1>
      <Formik
        initialValues={{
          firstName: ‘‘,
          lastName: ‘‘,
          email: ‘‘,
          acceptedTerms: false, // added for our checkbox
          jobType: ‘‘, // added for our select
        }}
        validationSchema={Yup.object({
          firstName: Yup.string()
            .max(15, ‘Must be 15 characters or less‘)
            .required(‘Required‘),
          lastName: Yup.string()
            .max(20, ‘Must be 20 characters or less‘)
            .required(‘Required‘),
          email: Yup.string()
            .email(‘Invalid email address‘)
            .required(‘Required‘),
          acceptedTerms: Yup.boolean()
            .required(‘Required‘)
            .oneOf([true], ‘You must accept the terms and conditions.‘),
          jobType: Yup.string()
            .oneOf(
              [‘designer‘, ‘development‘, ‘product‘, ‘other‘],
              ‘Invalid Job Type‘
            )
            .required(‘Required‘),
        })}
        onSubmit={(values, { setSubmitting }) => {
          setTimeout(() => {
            alert(JSON.stringify(values, null, 2));
            setSubmitting(false);
          }, 400);
        }}
      >
        <Form>
          <MyTextInput
            label="First Name"
            name="firstName"
            type="text"
            placeholder="Jane"
          />
          <MyTextInput
            label="Last Name"
            name="lastName"
            type="text"
            placeholder="Doe"
          />
          <MyTextInput
            label="Email Address"
            name="email"
            type="email"
            placeholder="[email protected]"
          />
          <MySelect label="Job Type" name="jobType">
            <option value="">Select a job type</option>
            <option value="designer">Designer</option>
            <option value="development">Developer</option>
            <option value="product">Product Manager</option>
            <option value="other">Other</option>
          </MySelect>
          <MyCheckbox name="acceptedTerms">
            I accept the terms and conditions
          </MyCheckbox>

          <button type="submit">Submit</button>
        </Form>
      </Formik>
    </>
  );
};

实际使用:

1.新建一个form表单元素的通用js代码如下:

import { useField } from ‘formik‘;
import React from ‘react‘;
export const MyTextInput = ({ label, ...props }) => {
    // useField() returns [formik.getFieldProps(), formik.getFieldMeta()]
    // which we can spread on <input> and also replace ErrorMessage entirely.
    const [field, meta] = useField(props);
    return (
        <>
        <label htmlFor={props.id || props.name}>{label}</label>
        <input className={meta.touched && meta.error?‘text-input error-input‘:‘text-input‘}  {...field} {...props} />
        {meta.touched && meta.error ? (
            <div className="error">{meta.error=="请输入"?meta.error+label:label+meta.error}</div>
        ) : null}
        </>
    );
};
export const MyCheckbox = ({ children, ...props }) => {
    // We need to tell useField what type of input this is
    // since React treats radios and checkboxes differently
    // than inputs/select/textarea.
    const [field, meta] = useField({ ...props, type: ‘checkbox‘ });
    return (
        <>
        <label className="checkbox">
            <input type="checkbox"  {...field} {...props} />
            {children}
        </label>
        {meta.touched && meta.error ? (
            <div className="error">{meta.error}</div>
        ) : null}
        </>
    );
};
export const MySelect = ({ label, ...props }) => {
    const [field, meta] = useField(props);
    return (
        <>
        <label htmlFor={props.id || props.name}>{label}</label>
        <select {...field} {...props} />
        {meta.touched && meta.error ? (
            <div className="error">{meta.error}</div>
        ) : null}
        </>
    );
};

2.新建一个统一校验规则js,代码如下:

import * as Yup from ‘yup‘
/* 设置提示文字 */
export function yupSetLocale(){
    Yup.setLocale({
        mixed: {
            required:‘请输入‘
        },
        string: {
            max: ‘字符最多${max}个‘
        },
    });
}
export const password = {‘message‘:‘规则提示信息‘,‘reg‘:/^(?![a-zA-z]+$)(?!\d+$)(?![[email protected]#$%^&*,.?></]+$)(?![a-z\d]+$)(?![A-Z\d]+$)(?![[email protected]#$%^&*,.?></]+$)(?![\[email protected]#$%^&*,.?></]+$)(?![[email protected]#$%^&*,.?></]+$)[a-zA-z\[email protected]#$%^&*,.?></]{8,20}$/}

3.使用

import React ,{Component} from ‘react‘
import { Formik, Field, Form, ErrorMessage } from ‘formik‘;
import {MyTextInput,MyCheckbox,MySelect} from ‘./../../../common/formItem‘
import * as Yup from ‘yup‘;
import * as myYup from ‘./../../../common/validator‘;
/* 设置提示文字 */
myYup.yupSetLocale();
 const SignupForm = () => {
            const formik = Yup.object({
                firstName: Yup.string()
                    .required().matches(myYup.password.reg,myYup.password.message),
                lastName: Yup.string()
                    .max(20)
                    .required(),
                email: Yup.string().email(‘Invalid email address‘).required(),
                acceptedTerms: Yup.boolean()
                    .required(‘请选择‘)
                    .oneOf([true], ‘你必须勾选‘),
                jobType: Yup.string().required(‘请选择‘),
            })
            return (
                <Formik
                    initialValues={{ firstName: ‘‘, lastName: ‘‘, email: ‘‘ }}
                    validationSchema={formik}
                    onSubmit={(values, { setSubmitting }) => {
                        setTimeout(() => {
                            alert(JSON.stringify(values, null, 2));
                            setSubmitting(false);
                        }, 400);
                    }}
                >
                    <Form>
                        <div>
                        <MyTextInput
                            label="姓名"
                            name="firstName"
                            type="text"
                            placeholder="Jane"
                        />
                        </div>
                        <div>
                        <MyTextInput
                            label="用户名"
                            name="lastName"
                            type="text"
                            placeholder="Doe"
                        />
                        </div>
                        <div>
                        <MyTextInput
                            label="邮箱"
                            name="email"
                            type="email"
                            placeholder="[email protected]"
                        />
                        </div>
                        <div>
                        <MySelect label="Job Type" name="jobType">
                            <option value="">Select a job type</option>
                            <option value="designer">Designer</option>
                            <option value="development">Developer</option>
                            <option value="product">Product Manager</option>
                            <option value="other">Other</option>
                        </MySelect>
                        </div>
                        <div>
                        <MyCheckbox name="acceptedTerms">
                            I accept the terms and conditions
                        </MyCheckbox>
                        </div>
                        <div>
                        <button type="submit" >Submit</button>
                        </div>
                    </Form>
                </Formik>
            );
        };

原文地址:https://www.cnblogs.com/xuexia/p/12090440.html

时间: 2024-10-29 08:30:29

react之form表单工具:formik+yup的相关文章

React 之form表单、select、textarea、checkbox使用

1.案例如下 import React from 'react'; /** * 非约束性组(类似defaultValue等属性,不可以程序修改): <input type="text" defaultValue="a" /> 这个 defaultValue 其实就是原生DOM中的 value 属性. 这样写出的来的组件,其value值就是用户输入的内容,React完全不管理输入的过程. 约束性组件(可以修改属性值): <input value={t

细说 Form (表单)

阅读目录 开始 简单的表单,简单的处理方式 表单提交,成功控件 多提交按钮的表单 上传文件的表单 MVC Controller中多个自定义类型的传入参数 F5刷新问题并不是WebForms的错 以Ajax方式提交整个表单 以Ajax方式提交部分表单 使用JQuery,就不要再拼URL了! id, name 有什么关系 使用C#模拟浏览器提交表单 资源链接 Form(表单)对于每个WEB开发人员来说,应该是再熟悉不过的东西了,可它却是页面与WEB服务器交互过程中最重要的信息来源. 虽然Asp.ne

Linux curl 模拟form表单提交信息和文件

curl是一个命令行方式下传输数据的开源传输工具,支持多种协议:FTP.HTTP.HTTPS.IMAP.POP3.TELNET等,功能超级强大. 我今天想说的是程序开发中常用的模拟Form提交 1.GET提交 特别简单直接写url里面 2.POST提交    通过 --data/-d 方式指定使用POST方式传递数据 3.模拟form表单提交文件  --form/-F 模拟form表单提交文件 这个命令超级好用,再也不用为了写上传接口,而被迫写一个Form表单了 "[email protecte

天河微信小程序入门《四》:融会贯通,form表单提交数据库

天河在阔别了十几天之后终于又回来了.其实这篇文章里的demo是接着(天河微信小程序入门<三>)后面就做了的,但是因为最近在做别的项目,所以就偷懒没有发出来.放到今天来看,从前台提交数据到数据库已经是没有什么可写的了.不过既然开篇了就不能太监么,所以还是分享出来给大家.我当时的目的是为了实验api的功能和跟后台数据的通讯存储,所以没有考虑到美观之类的,界面非常丑请大家包涵.一个带form表单的页面在这里定义好自己form表单的元素名称 01 02 03 04 05 06 07 08 09 10

Python之路【第十三篇续】jQuery案例-Form表单&amp;插件及扩展

jQuery案例-Form表单 学完这个form表单的案例,如果有人说这个表单(功能)还不够NB(此文不包含样式,样式是CSS比较简单可以根据需求自己添加),那么找武Sir他帮你搞定. 一步一步来 注意事项(目录结构): 在写前端html代码的时候要注意(任何代码都一样),一定要规划好目录结构方便其他的人来看你的代码! 如果还有其他的html页面可以在加一个html存储的文件夹. 1.首先看下HTML主体 <!DOCTYPE html> <html lang="en"

【转】细说 Form (表单)

阅读目录 开始 简单的表单,简单的处理方式 表单提交,成功控件 多提交按钮的表单 上传文件的表单 MVC Controller中多个自定义类型的传入参数 F5刷新问题并不是WebForms的错 以Ajax方式提交整个表单 以Ajax方式提交部分表单 使用JQuery,就不要再拼URL了! id, name 有什么关系 使用C#模拟浏览器提交表单 资源链接 Form(表单)对于每个WEB开发人员来说,应该是再熟悉不过的东西了,可它却是页面与WEB服务器交互过程中最重要的信息来源. 虽然Asp.ne

form表单提交数据编码方式和tomcat接受数据解码方式的思考

http://blog.sina.com.cn/s/blog_95c8f1ac010198j2.html ******************************************************* form有2中方法把数据提交给服务器,get和post,分别说下吧. (一)get提交 1.首先说下客户端(浏览器)的form表单用get方法是如何将数据编码后提交给服务器端的吧. 对于get方法来说,都是把数据串联在请求的url后面作为参数,如:http://localhost:

JavaScript之form表单的序列化和json化[form.js]

一.应用场景 form提交时,使用ajax提交. 二.效果 通过本工具,实现表单所有form的快速序列化和json化,使前端人员在ajax提交form表单的时,脱离重复性的,大劳动量的手动抽取form属性和对应的值. 三.源码[form.js] //将数据序列化成 url请求方式的编码 function serialize(form){ var len=form.elements.length;//表单字段长度;表单字段包括<input><select><button>

Python之路【第十三篇】jQuery案例-Form表单&amp;插件及扩展

学完这个form表单的案例,如果有人说这个表单(功能)还不够NB(此文不包含样式,样式是CSS比较简单可以根据需求自己添加),那么找武Sir他帮你搞定. 一步一步来 注意事项(目录结构): 在写前端html代码的时候要注意(任何代码都一样),一定要规划好目录结构方便其他的人来看你的代码! 如果还有其他的html页面可以在加一个html存储的文件夹. 1.首先看下HTML主体 <!DOCTYPE html> <html lang="en"> <head>