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

React多元素点击弹窗展示问题:useRef传引用报错求解决方案

问题分析与解决方案

首先明确:不能直接渲染useRef存储的真实DOM节点,React的渲染系统只能处理React元素(JSX),而expendRef.current是浏览器生成的真实HTMLDivElement对象,直接放进JSX会触发类型错误。

先修正你代码里的基础错误

你的代码存在几个语法/写法问题,先修正这些才能正常运行:

  1. 缺少useState和useRef的解构导入
  2. Popup组件写法错误,函数组件无需render方法,直接返回JSX即可
  3. onClick事件的箭头函数括号未闭合
  4. expendRef.current?.parentNode是DOM节点,不能直接作为React子元素渲染

修正后的基础代码(仍未解决核心需求):

import React, { useState, useRef } from "react";

const Summary = () => {
  const [expand, setExpand] = useState(false);
  const expendRef = useRef<HTMLDivElement>(null);

  return (
    <div>
      {expand && <Popup show={expand} />}
      <div
        ref={expendRef}
        className='summary-table col-md-6'
        onClick={() => setExpand(!expand)}
      >
        Reference element
      </div>
    </div>
  );
};

const Popup = (props) => {
  return (
    <>
      <h1>Popup Element</h1>
      <div>{props.children}</div>
    </>
  );
};

export default Summary;

可行实现方案

方案1:存储元素对应的业务数据(推荐)

不要存储DOM节点,而是把每个元素的详情数据存起来,点击时将对应数据传给弹窗渲染。这是多元素场景(如联系人网格)最常用的方案:

import React, { useState } from "react";

// 模拟联系人数据
const contacts = [
  { id: 1, name: "张三", phone: "138xxxx1234", email: "zhangsan@example.com" },
  { id: 2, name: "李四", phone: "139xxxx5678", email: "lisi@example.com" },
];

const Summary = () => {
  const [selectedContact, setSelectedContact] = useState(null);

  return (
    <div>
      {/* 弹窗:根据选中的联系人渲染详情 */}
      {selectedContact && (
        <Popup onClose={() => setSelectedContact(null)}>
          <div>
            <h2>{selectedContact.name}</h2>
            <p>电话:{selectedContact.phone}</p>
            <p>邮箱:{selectedContact.email}</p>
          </div>
        </Popup>
      )}

      {/* 联系人网格 */}
      <div className="contacts-grid">
        {contacts.map(contact => (
          <div
            key={contact.id}
            className='summary-table col-md-6'
            onClick={() => setSelectedContact(contact)}
          >
            {contact.name}
          </div>
        ))}
      </div>
    </div>
  );
};

const Popup = ({ onClose, children }) => {
  return (
    <div className="popup-overlay" onClick={onClose}>
      <div className="popup-content" onClick={(e) => e.stopPropagation()}>
        <button onClick={onClose}>关闭</button>
        {children}
      </div>
    </div>
  );
};

export default Summary;

方案2:抽离可复用的内容组件

如果需要复用原元素的UI样式,可以把元素的内容抽成独立组件,点击时在弹窗里重新渲染该组件:

import React, { useState } from "react";

// 抽离可复用的内容组件
const ContactCard = ({ contact }) => (
  <div className='summary-card'>
    <h3>{contact.name}</h3>
    <p>电话:{contact.phone}</p>
  </div>
);

const Summary = () => {
  const [selectedContact, setSelectedContact] = useState(null);

  return (
    <div>
      {selectedContact && (
        <Popup onClose={() => setSelectedContact(null)}>
          <ContactCard contact={selectedContact} />
        </Popup>
      )}

      <div className="contacts-grid">
        {contacts.map(contact => (
          <div
            key={contact.id}
            className='summary-table col-md-6'
            onClick={() => setSelectedContact(contact)}
          >
            <ContactCard contact={contact} />
          </div>
        ))}
      </div>
    </div>
  );
};

// Popup组件同方案1
const Popup = ({ onClose, children }) => {
  return (
    <div className="popup-overlay" onClick={onClose}>
      <div className="popup-content" onClick={(e) => e.stopPropagation()}>
        <button onClick={onClose}>关闭</button>
        {children}
      </div>
    </div>
  );
};

export default Summary;

为什么不能直接渲染DOM节点?

React基于虚拟DOM机制工作,要求渲染的是React元素(JSX编译后的对象)。真实DOM节点是浏览器创建的原生对象,无法被React纳入虚拟DOM的更新流程,直接放入JSX会触发类型不匹配的错误。

内容的提问来源于stack exchange,提问作者Anurag Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 09:25:36