创见博客
为什么函数组件无实例,类组件有实例
七崽爱吃小饼干2026/01/08阅读 0专栏 React

核心本质:两种组件的底层实现逻辑不同

React 对类组件和函数组件的定位、执行方式从根源上就不一样,这直接决定了“是否有实例”:

  • 类组件:是基于 ES6 类(Class)的实例化机制,每渲染一个类组件,就会创建一个类的实例,实例用来承载组件的状态、生命周期、方法等;
  • 函数组件:本质就是普通的 JavaScript 函数,每次渲染都是一次“函数调用”,调用完就执行完毕,没有持久化的实例对象来承载状态(Hook 是通过 React 内部的“链表”单独管理状态,而非绑定到组件实例)。

1. 类组件:天生有实例(ES6 Class 特性)

React 类组件的本质是 继承自 React.Component 的 ES6 类,而 ES6 类的核心特性就是“实例化”:

(1)类组件的执行过程

jsx
// 类组件定义
class ClassInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: '' }; // 状态挂载在实例上
    this.focus = this.focus.bind(this); // 方法绑定在实例上
  }

  focus() {
    this.inputRef.focus(); // 通过实例访问 DOM ref
  }

  render() {
    return <input ref={el => this.inputRef = el} />;
  }
}

// 父组件使用
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.classInputRef = React.createRef(); // 指向类组件实例
  }

  handleFocus() {
    this.classInputRef.current.focus(); // 调用实例上的 focus 方法
  }

  render() {
    // 渲染 ClassInput 时,React 会 new ClassInput(props) 创建实例
    return (
      <div>
        <ClassInput ref={this.classInputRef} />
        <button onClick={() => this.handleFocus()}>聚焦</button>
      </div>
    );
  }
}

(2)类组件有实例的核心原因

  1. 实例是状态/方法的载体:类组件的 state、this.props、自定义方法(如 focus)都挂载在实例上,没有实例就无法存储这些“持久化”的内容;
  2. React 主动实例化:当渲染 <ClassInput /> 时,React 内部会执行 new ClassInput(props),生成一个唯一的实例,这个实例会伴随组件的整个生命周期(挂载 → 更新 → 卸载);
  3. ref 直接指向实例:给类组件绑 ref,ref.current 就是这个实例,所以能直接调用实例上的方法(如 focus)。

2. 函数组件:天生无实例(普通函数特性)

React 函数组件的本质是 接收 props 并返回 JSX 的普通函数,普通函数的执行特性是“调用即执行,执行完销毁”,没有“实例”的概念:

(1)函数组件的执行过程

jsx
// 函数组件定义
function FuncInput(props) {
  const inputRef = useRef(null); // Hook 状态由 React 内部管理,而非实例
  const focus = () => {
    inputRef.current.focus();
  };

  return <input ref={inputRef} />;
}

// 父组件使用
function Parent() {
  const funcInputRef = useRef(null); // 试图绑 ref 到函数组件

  useEffect(() => {
    console.log(funcInputRef.current); // undefined(无实例)
  }, []);

  return <FuncInput ref={funcInputRef} />; // 函数组件无实例,ref 赋值为 undefined
}

(2)函数组件无实例的核心原因

  1. 函数调用无持久化载体:每次渲染函数组件,都是一次普通的函数调用(FuncInput(props)),函数执行完毕后,内部的变量(如 inputRef、focus)会被纳入 React 的 Hook 管理体系,但函数本身不会留下任何“实例对象”;
  2. React 不实例化函数组件:React 渲染函数组件时,只会执行函数、获取返回的 JSX,不会像类组件那样执行 new FuncInput(props),自然不会生成实例;
  3. Hook 替代了实例的作用:函数组件的状态(useState)、ref(useRef)、生命周期(useEffect)等,都由 React 内部通过“Hook 链表”来管理(每个函数组件对应的 Fiber 节点上挂载 Hook 链表),不需要依赖实例作为载体;
  4. 设计初衷就是“无状态”:函数组件最初的设计目标是“纯函数组件”(无状态、无副作用),核心是“输入 props,输出 JSX”,实例会增加额外的内存开销,违背轻量设计。

3. 关键对比:实例的有无对开发的影响

特性类组件函数组件
实例存在性有(ES6 Class 实例)无(普通函数调用,无实例)
状态载体实例(this.state)React 内部 Hook 链表
ref 指向组件实例undefined(无 forwardRef 时)
方法调用通过实例调用(this.xxx)需通过 forwardRef + useImperativeHandle 暴露

总结

  1. 类组件有实例:因为类组件是 ES6 Class,React 渲染时会主动 new 出实例,实例作为状态、方法的载体,ref 可直接指向实例;
  2. 函数组件无实例:因为函数组件是普通函数,React 仅执行函数获取 JSX,无实例化过程,状态由 Hook 链表管理,而非实例,所以绑 ref 会得到 undefined;
  3. forwardRef 的作用:函数组件无实例,所以需要 forwardRef 把 ref “转发”到内部 DOM 节点/类组件实例,才能让父组件拿到可操作的目标。

简单记:类组件 = 有实例的“对象”,函数组件 = 无实例的“函数调用”,这是 React 两种组件模型最核心的区别之一。

评论
0/100