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

React中右键上下文菜单无法动态传递标签名问题求助

问题解决:React侧边栏右键菜单无法动态显示当前标签名

问题现象

在React项目的树形结构左侧侧边栏菜单中,右键点击任意标签,弹出的上下文菜单里的Open-{{标签名}}选项始终显示最后一个标签的名称,无法动态匹配当前点击的标签。

问题原因

  1. 组件调用方式错误:PackageDesignerContextMenu组件直接以函数调用的方式执行ContextMenu({...props}),而非通过React的JSX语法渲染组件。这种写法会导致useContextMenu钩子的上下文无法在多个组件实例间正确隔离,从而出现状态共享、最后一个实例的属性覆盖所有实例的问题。
  2. buildMenu参数传递不当:调用buildMenu(items, name)时,第二个参数传递了重复的name值,可能导致菜单标识冲突,进一步引发上下文菜单的状态混淆。

修复方案

1. 修正组件调用方式

将PackageDesignerContextMenu改为返回JSX元素的标准React组件写法,确保每个实例拥有独立的上下文。

2. 调整buildMenu的参数传递

buildMenu的第二个参数应为唯一标识,使用labelname(确保每个标签唯一)替代name,避免重复导致的状态冲突。

完整修复后的代码

import { TooltipDefinition } from 'carbon-components-react';
import { useContextMenu } from 'carbon-components-react/lib/components/ContextMenu';
import Menu from 'carbon-components-react/lib/components/Menu';
import { buildMenu } from 'carbon-components-react/lib/components/Menu/_storybook-utils';
import PropTypes from 'prop-types';
import React from 'react';

export const getBoldTeXt = (name, elementSearch) => {
  const splittedNames = name?.split(new RegExp(`(${elementSearch})`, 'gi'));
  return (
    <>
      {splittedNames &&
        splittedNames
          .filter((splittedName) => splittedName.trim() !== '')
          .map((splittedName, i) => (
            <span
              key={i}
              style={
                elementSearch && splittedName && splittedName.toLowerCase() === elementSearch.toLowerCase()
                  ? { fontWeight: 'bold' }
                  : {}
              }
            >
              {splittedName}
            </span>
          ))}
    </>
  );
};

const renderToolTip = (name, elementSearch, labelname, istruncated) => {
  if (istruncated) {
    return (
      <TooltipDefinition tooltipText={name} alignment='start' direction='bottom'>
        {name !== undefined ? getBoldTeXt(labelname, elementSearch) : ''}
      </TooltipDefinition>
    );
  } else if (name !== undefined) {
    return getBoldTeXt(labelname, elementSearch);
  }
};

const ContextMenu = ({ name, elementSearch, labelname, istruncated, version }) => {
  const menuProps = useContextMenu();

  let items = [
    {
      type: 'item',
      label: `Open-${name}`,
    },
    { type: 'divider' },
  ];
  // 使用labelname作为唯一标识,避免重复
  const renderedItems = buildMenu(items, labelname);

  return (
    <>
      <span className='package-row-name'>{renderToolTip(name, elementSearch, labelname, istruncated)}</span>
      <span className='version'>{version}</span>
      <Menu {...menuProps}>{renderedItems}</Menu>
    </>
  );
};

// 修正组件写法,返回JSX元素
export const PackageDesignerContextMenu = ({ name, elementSearch, labelname, istruncated, version }) => (
  <ContextMenu 
    name={name} 
    elementSearch={elementSearch} 
    labelname={labelname} 
    istruncated={istruncated} 
    version={version} 
  />
);

ContextMenu.propTypes = {
  name: PropTypes.string,
  elementSearch: PropTypes.string,
  labelname: PropTypes.string.isRequired,
  istruncated: PropTypes.string.isRequired,
  version: PropTypes.string,
};

父组件调用代码(无需修改)

<PackageDesignerContextMenu
  name={name}
  elementSearch={elementSearch}
  labelname={labelname}
  istruncated={istruncated}
  version={version}
/>

关键修复点说明

  • 将PackageDesignerContextMenu从直接调用ContextMenu函数改为返回<ContextMenu />JSX元素,确保每个组件实例拥有独立的React上下文,useContextMenu钩子能正确绑定到当前实例。
  • 调整buildMenu的第二个参数为labelname(确保每个标签唯一),避免因标识重复导致的菜单状态混淆。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 06:06:07