【react】 form表单校验逻辑封装
好的,接下来我们将创建一个可复用的 React 表单校验封装组件。我们将使用 React 的状态和上下文功能来管理表单的校验状态和错误信息。我们还将实现一些常见的校验规则,并使其易于扩展。
实现步骤
- 创建一个
FormProvider
组件来提供表单上下文。 - 创建一个
useForm
钩子来使用表单上下文。 - 创建一个
useField
钩子来管理单个表单字段的状态和校验。 - 创建一些常见的校验规则。
- 创建示例表单来展示如何使用这些封装组件。
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 表单校验封装,包括:
- 创建表单上下文并提供表单注册和校验功能。
- 创建自定义钩子来管理单个表单字段的状态和校验。
- 实现 TextInput 文本框的校验规则并在表单组件中使用。
这样可以轻松扩展和复用表单校验逻辑。你可以根据自己的需求增加更多的校验规则和表单字段类型。