You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 00:09:03