React中右键上下文菜单无法动态传递标签名问题求助
问题解决:React侧边栏右键菜单无法动态显示当前标签名
问题现象
在React项目的树形结构左侧侧边栏菜单中,右键点击任意标签,弹出的上下文菜单里的Open-{{标签名}}选项始终显示最后一个标签的名称,无法动态匹配当前点击的标签。
问题原因
- 组件调用方式错误:
PackageDesignerContextMenu组件直接以函数调用的方式执行ContextMenu({...props}),而非通过React的JSX语法渲染组件。这种写法会导致useContextMenu钩子的上下文无法在多个组件实例间正确隔离,从而出现状态共享、最后一个实例的属性覆盖所有实例的问题。 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
相关产品推荐
相关产品推荐

