Formik introduction and basic use

1 Formik Introduction

1.1 Introduction to FormIk

FormIk is a third-party component library officially recommended by React to enhance form functionality. With formik, we can focus more on our business logic without being distracted from dealing with some details on the basis of the form.

It helps us enhance form care and simplify form processing.

1.2 FormIk Download

npm install formik

2 FormIk enhanced form

2.1 Basic use of Formik

Use formik for form data binding and form submission processing

import { memo, useState } from 'react'
import { useFormik } from 'formik'

function App () {
  const formik = useFormik({
    initialValues: {
      username: '',
      password: ''
    },
    onSubmit: values => {
      // 这里formik 已经默认帮我们阻止了默认执行
      console.log(values)
    }
  })
  return (
    <div>
      <form onSubmit={formik.handleSubmit}>
        <label htmlFor='username'>用户名</label>
        <input
          type='text'
          name='username'
          value={formik.values.username}
          onChange={formik.handleChange}
        />
        <label htmlFor='password'>密码</label>
        <input
          type='password'
          name='password'
          value={formik.values.password}
          onChange={formik.handleChange}
        />
        <button type='submit'>提交</button>
      </form>
    </div>
  )
}

export default memo(App)

2.2 formik form validation

2.2.1 Initial verification method

Configure the validate attribute when useFomik is a function, which receives the value of the form, and the value of the form can be verified inside the function. The function finally returns an object to describe the validation error results of the fields in the form.

2.2.3 Improve user experience when verifying error messages

When an error message is displayed, formik.touched.xxx can be used to check whether the form element has been changed. Before that, you need to add the onBlur event processing function onBlur={formik.handleBlur} to the expression element of the input, that is, start the verification when the mouse leaves the focus.

import { memo } from 'react'
import { useFormik } from 'formik'

function App () {
  const formik = useFormik({
    // validateOnChange: false,
    // validateOnBlur: true,
    initialValues: {
      username: '',
      password: ''
    },
    onSubmit: values => {
      console.log(values)
    },
    validate: values => {
      const errors = {}
      if (!values.username || values.username.trim() === '') {
        errors.username = '用户名不能为空'
      } else if (values.username.length > 15) {
        errors.username = '用户名长度不能大于15位'
      }

      if (values.password.length < 6) {
        errors.password = '密码长度不能小于6位'
      }
      console.log('validate....', errors)
      return errors
    }
  })
  return (
    <div>
      <form onSubmit={formik.handleSubmit}>
        <div>
          <label htmlFor='username'>用户名</label>
          <input
            id='username'
            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>
        </div>
        <div>
          <label htmlFor='password'>密&nbsp;&nbsp;&nbsp;&nbsp;码</label>
          <input
            id='password'
            type='password'
            name='password'
            value={formik.values.password}
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
          />
          <p>
            {formik.touched.username && formik.errors.password
              ? formik.errors.password
              : null}
          </p>
        </div>
        <button type='submit'>提交</button>
      </form>
    </div>
  )
}

export default memo(App)

2.2.2 Use yup to verify the form

2.2.2.1 download yup
npm install yup
2.2.2.2 How to use yup
  • Define validation rules

To use yup with Formik to achieve validation, you need to configure the validationSchema option, which is an object produced by Yup.object({}). At this time, we can remove the validate function, and the code for validation becomes much more concise, and it becomes a writing process. Describes the form of an object. And the others are unchanged.

import { memo } from 'react'
import { useFormik } from 'formik'
import * as Yup from 'yup'

function App () {
  const formik = useFormik({
    // validateOnChange: false,
    // validateOnBlur: true,
    initialValues: {
      username: '',
      password: ''
    },
    onSubmit: values => {
      console.log(values)
    },
    /* validate: values => {
      const errors = {}
      if (!values.username || values.username.trim() === '') {
        errors.username = '用户名不能为空'
      } else if (values.username.length > 15) {
        errors.username = '用户名长度不能大于15位'
      }

      if (values.password.length < 6) {
        errors.password = '密码长度不能小于6位'
      }
      console.log('validate....', errors)
      return errors
    } */
    // 使用yup 实现验证需要配置 validationSchema, 配置位Yup.object({})所生产的一个对象
    validationSchema: Yup.object({
      username: Yup.string()
        .max(15, '用户名长度不能大于15位')
        .required('请填写用户名'),
      password: Yup.string()
        .min(6, '密码长度不能小于6位')
        .required('请填写密码')
    })
  })
  return (
    <div>
      <form onSubmit={formik.handleSubmit}>
        <div>
          <label htmlFor='username'>用户名</label>
          <input
            id='username'
            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>
        </div>
        <div>
          <label htmlFor='password'>密&nbsp;&nbsp;&nbsp;&nbsp;码</label>
          <input
            id='password'
            type='password'
            name='password'
            value={formik.values.password}
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
          />
          <p>
            {formik.touched.username && formik.errors.password
              ? formik.errors.password
              : null}
          </p>
        </div>
        <button type='submit'>提交</button>
      </form>
    </div>
  )
}

export default memo(App)

2.3 Use the getFieldProps method to simplify the form code

The getFieldProps method will help us return the value, onChange and onBlur properties in the input of the corresponding form item, and put them in an object. After getting it back, add it to the input tag in the form of {...getFieldProps('xxx')} , which can greatly simplify the page code we write form forms.

<input
    id='username'
    type='text'
    name='username'
    {...formik.getFieldProps('username')}
    />

Full code:

import { memo } from 'react'
import { useFormik } from 'formik'
import * as Yup from 'yup'

function App () {
  const formik = useFormik({
    // validateOnChange: false,
    // validateOnBlur: true,
    initialValues: {
      username: '',
      password: ''
    },
    onSubmit: values => {
      console.log(values)
    },
    /* validate: values => {
      const errors = {}
      if (!values.username || values.username.trim() === '') {
        errors.username = '用户名不能为空'
      } else if (values.username.length > 15) {
        errors.username = '用户名长度不能大于15位'
      }

      if (values.password.length < 6) {
        errors.password = '密码长度不能小于6位'
      }
      console.log('validate....', errors)
      return errors
    } */
    // 使用yup 实现验证需要配置 validationSchema, 配置位Yup.object({})所生产的一个对象
    validationSchema: Yup.object({
      username: Yup.string()
        .max(15, '用户名长度不能大于15位')
        .required('请填写用户名'),
      password: Yup.string()
        .min(6, '密码长度不能小于6位')
        .required('请填写密码')
    })
  })
  return (
    <div>
      <form onSubmit={formik.handleSubmit}>
        <div>
          <label htmlFor='username'>用户名</label>
          <input
            id='username'
            type='text'
            name='username'
            {...formik.getFieldProps('username')}
          />
          <p>
            {formik.touched.username && formik.errors.username
              ? formik.errors.username
              : null}
          </p>
        </div>
        <div>
          <label htmlFor='password'>密&nbsp;&nbsp;&nbsp;&nbsp;码</label>
          <input
            id='password'
            type='password'
            name='password'
            {...formik.getFieldProps('password')}
          />
          <p>
            {formik.touched.username && formik.errors.password
              ? formik.errors.password
              : null}
          </p>
        </div>
        <button type='submit'>提交</button>
      </form>
    </div>
  )
}

export default memo(App)

2.4 Use Formik's component form to build a form

The advantage is that it can make our form code look simpler, it provides Formik, Form, Field, ErrorMessage components.

import { memo } from 'react'
import * as Yup from 'yup'
import { Formik, Form, Field, ErrorMessage } from 'formik'

function App () {
  const initialValues = { username: '', password: '' }
  const handleSubmit = values => {
    console.log(values)
  }
  const validationSchema = Yup.object({
    username: Yup.string()
      .max(15, '用户名长度不能大于15位')
      .required('请填写用户名'),
    password: Yup.string()
      .min(6, '密码长度不能小于6位')
      .required('请填写密码')
  })
  return (
    <Formik
      initialValues={initialValues}
      onSubmit={handleSubmit}
      validationSchema={validationSchema}
    >
      <Form>
        <div>
          <label htmlFor='username'>用户名</label>
          <Field id='username' name='username' />
          <ErrorMessage name='username' />
        </div>
        <div>
          <label htmlFor='password'>密&emsp;码</label>
          <Field id='password' name='password' />
          <ErrorMessage name='password' />
        </div>
        <input type='submit' />
      </Form>
    </Formik>
  )
}

export default memo(App)

2.5 Use Formik components to build other form items

By default, the Field component renders a text box. To generate other form elements, you can use the following syntax:

import { memo } from 'react'
import * as Yup from 'yup'
import { Formik, Form, Field, ErrorMessage } from 'formik'

function App () {
  const initialValues = {
    username: '张三',
    password: '',
    content: '文章整挺好啊',
    subject: 'Java'
  }
  const handleSubmit = values => {
    console.log(values)
  }
  const validationSchema = Yup.object({
    username: Yup.string()
      .max(15, '用户名长度不能大于15位')
      .required('请填写用户名'),
    password: Yup.string()
      .min(6, '密码长度不能小于6位')
      .required('请填写密码')
  })
  return (
    <Formik
      initialValues={initialValues}
      onSubmit={handleSubmit}
      validationSchema={validationSchema}
    >
      <Form>
        <div>
          <label htmlFor='username'>用户名</label>
          <Field id='username' name='username' />
          <ErrorMessage name='username' />
        </div>
        <div>
          <label htmlFor='password'>密&emsp;码</label>
          <Field id='password' type='password' name='password' />
          <ErrorMessage name='password' />
        </div>
        <div>
          <h2>使用Formik的 Field组件 编写其他表单元素</h2>
          <div>
            <label htmlFor='content'>文章内容</label>
            <Field id='content' name='content' as='textarea'></Field>
          </div>
          <div>
            <label htmlFor='content'>文章内容</label>
            <Field id='subject' name='subject' as='select'>
              <option value='前端'>前端</option>
              <option value='Java'>Java</option>
              <option value='Python'>Python</option>
            </Field>
          </div>
        </div>
        <input type='submit' />
      </Form>
    </Formik>
  )
}

export default memo(App)

2.6 Use useField to build custom form controls

For example, Formik does not provide us with radio buttons, check boxes, etc., so we need to build these form controls ourselves. Need to use the useField method. Custom form spaces are actually components.

import { memo } from 'react'
import * as Yup from 'yup'
import { Formik, Form, Field, ErrorMessage, useField } from 'formik'
/**
 * 自定义密码表单控件演示案例
 * @param {*} param0
 * @returns
 */
function PasswordInputField ({ label, ...props }) {
  const [field, meta] = useField(props)
  console.log(field, meta)
  return (
    <div>
      <label htmlFor={props.id}>{label}</label>
      <input {...field} {...props} />
      {meta.touched && meta.error ? <span>{meta.error}</span> : null}
    </div>
  )
}

function App () {
  const initialValues = {
    username: '张三',
    password: '',
    password2: 'mymima',
    content: '文章整挺好啊',
    subject: 'Java'
  }
  const handleSubmit = values => {
    console.log(values)
  }
  const validationSchema = Yup.object({
    username: Yup.string()
      .max(15, '用户名长度不能大于15位')
      .required('请填写用户名'),
    password: Yup.string()
      .min(6, '密码长度不能小于6位')
      .required('请填写密码'),
    password2: Yup.string()
      .min(6, '密码2长度不能小于6位')
      .required('请填写密码2')
  })
  return (
    <Formik
      initialValues={initialValues}
      onSubmit={handleSubmit}
      validationSchema={validationSchema}
    >
      <Form>
        <div>
          <label htmlFor='username'>用户名</label>
          <Field id='username' name='username' />
          <ErrorMessage name='username' />
        </div>
        <div>
          <label htmlFor='password'>密&emsp;码</label>
          <Field id='password' type='password' name='password' />
          <ErrorMessage name='password' />
        </div>
        <PasswordInputField
          id='password2'
          type='password'
          name='password2'
          label='密&emsp;码'
          placeholder='请输入密码'
        />
        <div>
          <h2>使用Formik的 Field组件 编写其他表单元素</h2>
          <div>
            <label htmlFor='content'>文章内容</label>
            <Field id='content' name='content' as='textarea'></Field>
          </div>
          <div>
            <label htmlFor='content'>文章内容</label>
            <Field id='subject' name='subject' as='select'>
              <option value='前端'>前端</option>
              <option value='Java'>Java</option>
              <option value='Python'>Python</option>
            </Field>
          </div>
        </div>
        <input type='submit' />
      </Form>
    </Formik>
  )
}

export default memo(App)

2.7 Use useField to build a custom form control checkbox case

Write a check box control that allows the user to select multiple items from a list of options.

import { memo } from 'react'
import * as Yup from 'yup'
import { Formik, Form, Field, ErrorMessage, useField } from 'formik'

function CheckBox ({ label, ...props }) {
  // useField 返回数组 [FieldInputProps<any>, FieldMetaProps<any>, FieldHelperProps<any>]
  // 其中:FieldHelperProps 是提供给我们对field 的值或改动状态进行修改的方法的
  const [field, meta, helper] = useField(props)

  const { value } = meta
  const { setValue } = helper
  const handleChange = () => {
    // 利用 Set 集合快速去重拷贝数据
    const set = new Set(value)
    if (set.has(props.value)) {
      set.delete(props.value)
    } else {
      set.add(props.value)
    }

    // 对数据进行增删后调用 setValue 更新状态值
    setValue([...set])
  }
  return (
    <div>
      <input
        checked={value.includes(props.value)}
        type='checkbox'
        {...props}
        onChange={handleChange}
      />
      <label htmlFor={props.id}>{label || props.value}</label>
    </div>
  )
}

function MultipleSelectField ({ label, options = [], ...props }) {
  const [field, meta] = useField(props)
  return (
    <div>
      {label ? <label htmlFor={props.id}>{label}</label> : null}
      <select multiple {...field} {...props}>
        <option disabled>请选择</option>
        {options.map(option => {
          return (
            <option key={option.name || option} value={option.value || option}>
              {option.name || option.value || option}
            </option>
          )
        })}
      </select>
      {meta.touched && meta.error ? <span>{meta.error}</span> : null}
    </div>
  )
}

/**
 * 自定义密码表单控件演示案例
 * @param {*} param0
 * @returns
 */
function PasswordInputField ({ label, ...props }) {
  const [field, meta] = useField(props)
  return (
    <div>
      {label ? <label htmlFor={props.id}>{label}</label> : null}
      <input {...field} {...props} />
      {meta.touched && meta.error ? <span>{meta.error}</span> : null}
    </div>
  )
}

function App () {
  const initialValues = {
    username: '张三',
    password: '',
    password2: 'mymima',
    content: '文章整挺好啊',
    subject: 'Java',
    hobbies: ['吃饭', '睡觉'],
    careers: ['前端开发']
  }
  const handleSubmit = values => {
    console.log(values)
  }
  const validationSchema = Yup.object({
    username: Yup.string()
      .max(15, '用户名长度不能大于15位')
      .required('请填写用户名'),
    password: Yup.string()
      .min(6, '密码长度不能小于6位')
      .required('请填写密码'),
    password2: Yup.string()
      .min(6, '密码2长度不能小于6位')
      .required('请填写密码2'),
    hobbies: Yup.array()
      .min(1, '必须发展一个爱好')
      .max(2, '最多发展2个爱好')
  })
  return (
    <Formik
      initialValues={initialValues}
      onSubmit={handleSubmit}
      validationSchema={validationSchema}
    >
      <Form>
        <div>
          <label htmlFor='username'>用户名</label>
          <Field id='username' name='username' />
          <ErrorMessage name='username' />
        </div>
        <div>
          <label htmlFor='password'>密&emsp;码</label>
          <Field id='password' type='password' name='password' />
          <ErrorMessage name='password' />
        </div>
        <p>自定义的表单控件</p>
        <PasswordInputField
          id='password2'
          type='password'
          name='password2'
          label='密&emsp;码'
          placeholder='请输入密码'
        />
        <MultipleSelectField
          id='hobbies'
          type='select'
          name='hobbies'
          label='爱&emsp;好'
          placeholder='请选择爱好'
          options={['吃饭', '睡觉', '打豆豆']}
        />
        <h3>职&emsp;业</h3>
        <CheckBox id='前端开发xxx' value='前端开发' name='careers' />
        <CheckBox id='Java开发xxx' value='Java开发' name='careers' />
        <CheckBox id='全栈开发xxx' value='全栈开发' name='careers' />
        <div>
          <h2>使用Formik的 Field组件 编写其他表单元素</h2>
          <div>
            <label htmlFor='content'>文章内容</label>
            <Field id='content' name='content' as='textarea'></Field>
          </div>
          <div>
            <label htmlFor='content'>文章内容</label>
            <Field id='subject' name='subject' as='select'>
              <option value='前端'>前端</option>
              <option value='Java'>Java</option>
              <option value='Python'>Python</option>
            </Field>
          </div>
        </div>
        <input type='submit' />
      </Form>
    </Formik>
  )
}

export default memo(App)

Guess you like

Origin blog.csdn.net/u011024243/article/details/128627113