当前位置: 首页 > 工具软件 > Formik > 使用案例 >

Formik 表单处理组件(React学习笔记)

徐景明
2023-12-01

Formik增强表单的处理能力,简化表单的处理流程

安装 Formik 组件

npm i formik

基本用法

  • 使用formik进行表单数据绑定及表单提交处理操作
  • useFormik 方法接收一个对象,返回值也是一个对象
    • initialValues为初始化数据值
    • onSubmit 为表单提交方法, 形参 values 表单提交行为获取的数据
  • 表单通过name进行绑定
  • handleSubmit 表单提交方法,自动绑定onSubmit
  • formik.handleChange 方法,用于同步对应表单值
import { useFormik } from 'formik'

function App() {
  const formik = useFormik({
    initialValues: { username: '假装文艺浪' },
    onSubmit: values => { console.log(values) }
  })
  return <form onSubmit={formik.handleSubmit}>
    <input type="text" name="username" value={formik.values.username} onChange={formik.handleChange} />
    <input type="submit" />
  </form>
}

export default App

表单验证

基础验证

  • validate 用于表单校验,返回一个自定义对象 errors, 在内部写验证函数
  • formik.errors 可以获取验证结果
import { useFormik } from 'formik'

function App() {
  const formik = useFormik({
    initialValues: { username: '假装文艺浪', password: '123' },
    validate: values => {
      console.log(values)
      const errors = {}
      if (!values.username) errors.username = '请输入用户名'
      if (!values.password) errors.password = '请输入密码'
      return errors
    },
    onSubmit: values => { console.log(values) }
  })
  return <form onSubmit={formik.handleSubmit}>
    <input
      type="text"
      name="username"
      value={formik.values.username}
      onChange={formik.handleChange} />
    <p>{formik.errors.username ? <div>{formik.errors.username}</div> : null}</p>
    <input
      type="password" name="password"
      value={formik.values.password}
      onChange={formik.handleChange} />
    <p>{formik.errors.password ? <div>{formik.errors.password}</div> : null}</p>
    <input type="submit" />
  </form>
}

验证优化

  • 以上代码虽能完成验证功能,但用户体验并不好,当将默认值置空时,initialValues: { username: ‘’, password: ‘’ },在表单输入用户名,会发现密码的验证提示显示。 所以需要进一步优化以提高用户体验。
  • 开启离开焦点事件触发验证 onBlur={formik.handleBlur}
  • 判断当前的表单数据是否被更改formik.touched
  • 两者结合使用,缺一不可
import { useFormik } from 'formik'

function App() {
  const formik = useFormik({
    initialValues: { username: '', password: '' },
    validate: values => {
      console.log(values)
      const errors = {}
      if (!values.username) errors.username = '请输入用户名'
      if (!values.password) errors.password = '请输入密码'
      return errors
    },
    onSubmit: values => { console.log(values) }
  })
  return <form onSubmit={formik.handleSubmit}>
    <input
      type="text"
      name="username"
      value={formik.values.username}
      onChange={formik.handleChange}
      onBlur={formik.handleBlur} />
    <p>{formik.touched.username && formik.errors.username ? <div>{formik.errors.username}</div> : null}</p>
    <input
      type="password" name="password"
      value={formik.values.password}
      onChange={formik.handleChange}
      onBlur={formik.handleBlur} />
    <p>{formik.touched.password && formik.errors.password ? <div>{formik.errors.password}</div> : null}</p>
    <input type="submit" />
  </form>
}


export default App

使用 Yup 验证表单

  • yup下载
npm install yup

验证规则配置

  • Yup.object() 接收一对象,属性名与表单名一致,值为验证规则,可链式
  • validationSchema 存放验证规则
  • 相比较与之前的规则,显得简洁明了
import { useFormik } from 'formik';
import * as Yup from 'yup';

function App() {
  const formik = useFormik({
    initialValues: { username: '', password: '' },
    validationSchema: Yup.object({
      username: Yup.string()
        .max(12, '用户名的长度不能大于15')
        .required('请输入用户名'),
      password: Yup.string()
        .max(12, '密码的长度不能大于20')
        .min(6,'密码的长度不能小于6')
        .required('请输入密码')
    }),
    onSubmit: values => { console.log(values) }
  })
  return <form onSubmit={formik.handleSubmit}>
    <input
      type="text"
      name="username"
      value={formik.values.username}
      onChange={formik.handleChange}
      onBlur={formik.handleBlur} />
    <p>{formik.touched.username && formik.errors.username ? formik.errors.username: null}</p>
    <input
      type="password" name="password"
      value={formik.values.password}
      onChange={formik.handleChange}
      onBlur={formik.handleBlur} />
    <p>{formik.touched.password && formik.errors.password ? formik.errors.password : null}</p>
    <input type="submit" />
  </form>
}

减少样板代码

以上表单代码中,存在value、onChange、onBlur这些重复的代码

  • formik.getFieldProps(‘username’) 可以获取属性值,返回对象包含value、onChange、onBlur
{...formik.getFieldProps('username')}
  • 代码显得简洁
return <form onSubmit={formik.handleSubmit}>
    <input
      type="text"
      name="username"
      {...formik.getFieldProps('username')} />
    <p>{formik.touched.username && formik.errors.username ? formik.errors.username : null}</p>
    <input
      type="password" name="password"
      {...formik.getFieldProps('password')} />
    <p>{formik.touched.password && formik.errors.password ? formik.errors.password : null}</p>
    <input type="submit" />
  </form>

使用组件的方式构建表单

组件内封装好的组件

  • Formik 表单最外层,可传递数据
    • initialValue 表单默认数据
    • onSubmit 表单提交行为
    • validationSchema 表单验证规则
  • Form 表单组件
  • Field 具体表单项
  • ErrorMessage 表单项提示信息显示
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

function App() {
  const initialValues = {
    username: ''
  }
  const handleSubmit = (values) => {
    console.log(values)
  }
  const Schema = Yup.object({
    username: Yup.string()
      .max(12, '用户名长度不能大于12')
      .required('请输入用户名')
  })
  return <Formik 
    initialValues={initialValues}
    onSubmit={handleSubmit}
    validationSchema={Schema}
  >
    <Form>
      <Field name="username"></Field>
      <ErrorMessage name="username"></ErrorMessage>
      <input type='submit' />
    </Form>
  </Formik>
}
export default App

构建其他表单项

  • 默认情况下,Filed组件渲染的是文本框, 若要生成其他表单元素可以使用如下语法
  • as 指定类型
 <Field name="container" as="textarea" />
 <Field name="select" as="select" >
   <option value='React'>React</option>
   <option value='Vue'>Vue</option>
   <option value='Node'>Node</option>
 </Field>

构建自定义表单项

  • formik提供的表单控件不能构建密码框、复选框这些,需要自定义
  • 使用 useFiled 去构建自定义表单控件

表单控件

import { useField } from "formik";

function MyInput({label, ...props}) {
  // filed 表单属性  meta存放验证信息
  const [field, meta] = useField(props)
  return <div>
    <label htmlFor={props.id} >{label}</label>
    <input {...field} {...props} />
    {meta.touched && meta.error ? <span>{meta.error}</span> : null}
  </div>
}


<MyInput id="mypass" label="密码" type="password" name="password" placeholder="密码" />

自定义复选框控件

import React from "react";
import { useField } from "formik";

function MyCheckBox({ label, ...props }) {
  // helper 对象中 存方法
  const [field, meta, helper] = useField(props);
  const { value } = meta;
  const { setValue } = helper;
  // 复选框的逻辑实现
  const handleChange = () => {
    const set = new Set(value)
    if (set.has(props.value)) {
      set.delete(props.value) // 存在,删除
    } else {
      set.add(props.value) // 添加
    }
    setValue([...set])
  }
  return <div>
    <label htmlFor={props.id} >
      <input
        // 默认选中 
        checked={value.includes(props.value)}
        type="checkbox"
        {...props}
        onChange={handleChange} />
      {label}
    </label>
  </div>
}

<Checkbox value="足球" label="足球" name="hobbies" />
<Checkbox value="篮球" label="篮球" name="hobbies" />
<Checkbox value="橄榄球" label="橄榄球" name="hobbies" />
 类似资料: