如何将React中继承其他类组件的类组件转换为函数组件
继承类表单组件转函数组件实现方案
核心转换思路
React函数组件不存在类继承机制,所以我们将原本父类Form中封装的通用逻辑抽离为自定义Hook,原本通过继承实现的逻辑复用改为通过调用自定义Hook实现,公共UI渲染方法可以直接封装在Hook中返回给业务表单组件使用,原有的Input函数组件可以直接复用。
具体代码实现
1. 抽离公共逻辑为自定义Hook useForm.js
import { useState } from "react"; import Joi from "joi"; import Input from "./input"; const useForm = (initialData, schema, doSubmit) => { const [data, setData] = useState(initialData); const [errors, setErrors] = useState({}); const validate = () => { const options = { abortEarly: false }; const schemaJoi = Joi.object(schema); const { error } = schemaJoi.validate(data, options); if (!error) return null; const errors = {}; error.details.forEach(item => (errors[item.path[0]] = item.message)); return errors; }; const validateProperty = ({ name, value }) => { const obj = { [name]: value }; const fieldSchema = { [name]: schema[name] }; const schemaJoi = Joi.object(fieldSchema); const { error } = schemaJoi.validate(obj); return error ? error.details[0].message : null; }; const handleChange = ({ currentTarget: input }) => { const newErrors = { ...errors }; const errorMessage = validateProperty(input); if (errorMessage) newErrors[input.name] = errorMessage; else delete newErrors[input.name]; const newData = { ...data, [input.name]: input.value }; setData(newData); setErrors(newErrors); }; const handleSubmit = e => { e.preventDefault(); const validationErrors = validate(); setErrors(validationErrors || {}); if (validationErrors) return; doSubmit(data); }; const renderButton = (label) => { return ( <button disabled={!!validate()} className="btn btn-primary"> {label} </button> ); }; const renderInput = (name, label, type = "text") => { return ( <Input name={name} label={label} error={errors[name]} type={type} value={data[name]} onChange={handleChange} /> ); }; return { handleSubmit, renderInput, renderButton }; }; export default useForm;
2. 改造业务表单为函数组件 LoginForm.jsx
import Joi from "joi"; import useForm from "./useForm"; const LoginForm = () => { // 表单校验规则,和原有逻辑一致 const schema = { username: Joi.string().required().label("Username"), password: Joi.string().required().label("Password") }; // 表单初始值 const initialData = { username: "", password: "" }; // 表单校验通过后的提交逻辑 const doSubmit = (data) => { console.log("Submitted", data); }; // 调用自定义Hook获取表单方法 const { handleSubmit, renderInput, renderButton } = useForm(initialData, schema, doSubmit); return ( <div> <h1>Login</h1> <form onSubmit={handleSubmit}> {renderInput("username", "Username")} {renderInput("password", "Password", "password")} {renderButton("Login")} </form> </div> ); }; export default LoginForm;
方案说明
- 自定义Hook封装了所有原
Form父类的通用逻辑,每个业务表单调用Hook时会生成独立的状态,不会互相干扰,比类继承更灵活 - 原有逻辑完全保留,无需修改
Input组件,业务层代码改动量很小 - 如果需要新增其他表单(比如注册表单),只需要新写一个函数组件,传入对应的初始值、校验规则、提交逻辑调用
useForm即可,和原有继承的复用效率一致。
内容的提问来源于stack exchange,提问作者atazmak
相关产品推荐
相关产品推荐

