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

如何在基于React.createElement实现的可复用Heading组件中正确使用ref?

How to Add a Ref to a Dynamic Heading Component in React

Let's break down what's going wrong and fix your ref issue step by step.

What Caused the Error?

Your original approach had two key problems:

  1. Custom function components don't support refs by default: The Tag component you created inside Heading is a regular function component. When you tried to pass ref={headingRef} to it, TypeScript threw an error because function components don't include ref in their props unless you explicitly enable it with forwardRef.
  2. Incorrect React.createElement arguments: You tried to pass the ref as a fourth argument to createElement, but the correct structure is React.createElement(tag, propsObject, children). Any props (including ref) need to be part of the second argument object.

Solution 1: Simplify with Direct React.createElement Call

The easiest fix is to skip creating an internal Tag component entirely. Just pass the ref directly in the props object when calling createElement:

import React, { ReactNode, useRef, useEffect } from 'react';
import s from './Heading.scss';
import gsap from 'gsap';

interface HeadingProps {
  tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
  children: ReactNode;
  className?: string;
}

export const Heading = ({ tag, children, className }: HeadingProps) => {
  // Type the ref to match the heading DOM element
  const headingRef = useRef<HTMLHeadingElement>(null);

  // Example: Use GSAP for animation once the element mounts
  useEffect(() => {
    if (headingRef.current) {
      gsap.from(headingRef.current, { opacity: 0, y: 20, duration: 1 });
    }
  }, []);

  return React.createElement(
    tag,
    {
      className: s(s.heading, className),
      ref: headingRef // Attach ref directly to the dynamic heading element
    },
    children
  );
};

This works because React.createElement accepts all valid HTML attributes (including ref) for the specified tag, and TypeScript will correctly type-check the props against HTMLHeadingElement.

Solution 2: Use forwardRef If You Need a Custom Component

If you want to keep a separate component structure (for additional logic), use React.forwardRef to make your component accept and pass through refs to the underlying DOM element:

import React, { ReactNode, useRef, useEffect, forwardRef } from 'react';
import s from './Heading.scss';
import gsap from 'gsap';

interface HeadingProps {
  tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
  children: ReactNode;
  className?: string;
}

// Use forwardRef to enable ref support
const Heading = forwardRef<HTMLHeadingElement, HeadingProps>(({ tag, children, className }, ref) => {
  useEffect(() => {
    if (ref.current) {
      gsap.from(ref.current, { opacity: 0, y: 20, duration: 1 });
    }
  }, [ref]);

  return React.createElement(
    tag,
    {
      className: s(s.heading, className),
      ref: ref // Pass the forwarded ref to the dynamic heading
    },
    children
  );
});

export default Heading;

With forwardRef, the ref is passed as a second argument to your component, and you can attach it directly to the DOM element created by createElement. TypeScript will recognize the ref type (in this case, HTMLHeadingElement) to ensure type safety.

Key Takeaways

  • Avoid wrapping createElement in an unnecessary internal component unless you need extra logic.
  • For function components that need to expose a ref to their underlying DOM element, use forwardRef.
  • Always pass props (including ref) as part of the second argument to React.createElement.

内容的提问来源于stack exchange,提问作者Jesse Winton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 09:47:43