【react】 可复用 form 表单校验逻辑封装

【react】 form表单校验逻辑封装

好的,接下来我们将创建一个可复用的 React 表单校验封装组件。我们将使用 React 的状态和上下文功能来管理表单的校验状态和错误信息。我们还将实现一些常见的校验规则,并使其易于扩展。

实现步骤

  1. 创建一个 FormProvider 组件来提供表单上下文。
  2. 创建一个 useForm 钩子来使用表单上下文。
  3. 创建一个 useField 钩子来管理单个表单字段的状态和校验。
  4. 创建一些常见的校验规则。
  5. 创建示例表单来展示如何使用这些封装组件。

1. 创建 FormProvider.js

import React, { createContext, useContext, useState } from "react"

const FormContext = createContext()

export const FormProvider = ({ children, onSubmit }) => {
  const [fields, setFields] = useState({})
  const [checkedAll, setCheckedAll] = useState(false)

  const registerField = ({ name, label, validate, defaultValue }) => {
    setFields((prev) => ({
      ...prev,
      [name]: { name, label, value: defaultValue, validate, error: null }
    }))
  }

  const updateFieldValue = (name, value) => {
    const field = fields[name]
    if (field) {
      setFields((prev) => ({ ...prev, [name]: { ...prev[name], value } }))
    }
  }

  const setFieldError = (name, error) => {
    setFields((prev) => ({ ...prev, [name]: { ...prev[name], error } }))
  }

  const validateField = (name, value) => {
    const field = fields[name]
    if (field && field.validate) {
      const error = field.validate(value)
      setFieldError(name, error)
      return error
    }
    return null
  }

  const validateAllFields = (formData) => {
    let isValid = true
    Object.keys(formData).forEach((name) => {
      if (!!validateField(name, formData[name])) {
        isValid = false
      }
    })
    if (!isValid) {
      setCheckedAll(true)
    }
    return isValid
  }

  const handleSubmit = (event) => {
    event.preventDefault()
    const formData = Object.values(fields).reduce(
      (acc, field) => ({ ...acc, [field.name]: field.value }),
      {}
    )

    if (validateAllFields(formData)) {
      onSubmit(formData)
    }
  }

  return (
    <FormContext.Provider
      value={{
        registerField,
        validateField,
        updateFieldValue,
        checkedAll
      }}
    >
      <form onSubmit={handleSubmit}>{children}</form>
    </FormContext.Provider>
  )
}

export const useForm = () => {
  return useContext(FormContext)
}

2. 创建 useField.js

import { useState, useEffect } from "react"
import { useForm } from "./FormProvider"

const useField = ({ name, label, validate, defaultValue }) => {
  const { registerField, validateField, updateFieldValue, checkedAll } =
    useForm()
  const [value, setValue] = useState(defaultValue)
  const [error, setError] = useState(null)

  useEffect(() => {
      // 将 field 中的全部属性注入到 FormContext 管理
      registerField({ name, label, validate, defaultValue })
  }, [])

  useEffect(() => {
  	// 当 value 变化时,同步更新 field 中的 value 字段值
    updateFieldValue(name, value)
  }, [value])

  useEffect(() => {
    // 点击 submit 提交按钮,全局检测如果校验失败,显示错误信息
    if (validate && checkedAll) {
      const error = validateField(name, value)
      setError(error)
    }
  }, [validate, checkedAll])

  const handleChange = (e) => {
    const newValue = e.target.value
    setValue(newValue)
  }

  const handleBlur = () => {
    const error = validateField(name, value)
    setError(error)
  }

  return { value, error, handleChange, handleBlur }
}

export default useField

3. 创建一些常见的校验规则

// src/validationRules.js
export const required = (value) => {
  return value ? null : 'This field is required';
};

export const minLength = (min) => (value) => {
  return value.length >= min ? null : `Minimum length is ${min}`;
};

export const email = (value) => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(value) ? null : 'Invalid email address';
};

4. 创建示例表单 MyForm.js

import React from 'react';
import { FormProvider } from './FormProvider';
import useField from './useField';
import { required, minLength, email } from './validationRules';

// 简单实现 Form 表单中的 TextIput 组件,可根据需要自行扩展其他组件
const TextInput = ({ name, label, validate, defaultValue = "" }) => {
  const { value, error, handleChange, handleBlur } = useField({
    name,
    label,
    validate,
    defaultValue
  })

  return (
    <div>
      <label>{label}</label>
      <input
        name={name}
        value={value}
        onChange={handleChange}
        onBlur={handleBlur}
      />
      {error && <span style={{ color: "red" }}>{error}</span>}
    </div>
  )
}

const MyForm = () => {
  const handleSubmit = (values) => {
    console.log('Form Submitted!', values);
  };

  return (
    <FormProvider onSubmit={handleSubmit}>
      <TextInput name="username" label="Username" validate={required} />
      <TextInput name="email" label="Email" validate={email} />
      <TextInput name="password" label="Password" validate={minLength(6)} />
      <button type="submit">Submit</button>
    </FormProvider>
  );
};

export default MyForm;

5. 入口文件 index.js

import React from 'react';
import ReactDOM from 'react-dom';
import MyForm from './MyForm';

ReactDOM.render(
  <React.StrictMode>
    <MyForm />
  </React.StrictMode>,
  document.getElementById('root')
);

总结

通过以上步骤,我们实现了一个 React 表单校验封装,包括:

  1. 创建表单上下文并提供表单注册和校验功能。
  2. 创建自定义钩子来管理单个表单字段的状态和校验。
  3. 实现 TextInput 文本框的校验规则并在表单组件中使用。

这样可以轻松扩展和复用表单校验逻辑。你可以根据自己的需求增加更多的校验规则和表单字段类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值