NavMenu
是侧边导航菜单容器组件,负责:
onMenuClick
回调并传递给子组件NavMenu
├── Flex (垂直布局容器)
├── BusinessZone (业务功能区,可增长)
│ ├── 患者管理
│ ├── 检查
│ ├── 图像处理
│ └── 打印
└── SystemZone (系统功能区,固定)
├── 配置/帮助
└── 用户信息 (MeButton)
┌─────────────┐
│ BusinessZone│ ← flex-grow(占据剩余空间)
│ │
│ (滚动区域) │
│ │
├─────────────┤
│ SystemZone │ ← 固定高度,底部对齐
└─────────────┘
关键点:
h-full
(height: 100%)填充父容器NavMenu 不实现具体的导航逻辑,而是将两个专门的子组件组合在一起:
<Flex vertical className="h-full">
<BusinessZone onMenuClick={onClick} />
<SystemZone ref={systemZoneRef} onMenuClick={onClick} />
</Flex>
设计优势:
NavMenu 作为事件中继,将父组件的回调传递给子组件:
const onClick = (key: string) => {
onMenuClick?.(key);
};
// 传递给子组件
<BusinessZone onMenuClick={onClick} />
<SystemZone onMenuClick={onClick} />
作用:
const systemZoneRef = useRef<HTMLDivElement>(null);
<SystemZone ref={systemZoneRef} onMenuClick={onClick} />
可能的用途:
当前状态:已创建 ref 但未使用,可能是为未来功能预留
onMenuClick?: (key: string) => void
:菜单项点击回调函数渲染输出:垂直排列的导航菜单,包括:
事件传递:
onMenuClick
回调传递给子组件将多个小组件组合成一个大组件,而不是在一个组件中实现所有功能。
优势:
示例:
// 好的做法:组合
<NavMenu>
<BusinessZone />
<SystemZone />
</NavMenu>
// 不好的做法:单一组件实现所有功能
<NavMenu>
{/* 所有菜单项都在这里硬编码 */}
</NavMenu>
NavMenu 是一个典型的容器组件:
对比:
将 props 从父组件传递到子组件。
BasicLayout
↓ onMenuClick
NavMenu
↓ onMenuClick
BusinessZone / SystemZone
问题:
使用 CSS Flexbox 实现灵活的布局。
<Flex vertical className="h-full">
关键属性:
vertical
:垂直方向排列(flex-direction: column)h-full
:高度 100%,填充父容器flex-grow
占据剩余空间创建一个可变的 ref 对象,其值在组件的整个生命周期内保持不变。
const systemZoneRef = useRef<HTMLDivElement>(null);
用途:
onMenuClick?.(key);
等同于:
if (onMenuClick) {
onMenuClick(key);
}
优势:
NavMenu 接收事件回调,然后传递给子组件,形成事件委托链。
数据流:
用户点击菜单项
↓
BusinessZone/SystemZone 触发 onMenuClick
↓
NavMenu 的 onClick 函数
↓
父组件(BasicLayout)的 handleMenuClick
↓
Redux action dispatch
↓
状态更新
NavMenu 只负责一件事:组合和布局子组件。
好处:
const systemZoneRef = useRef<HTMLDivElement>(null);
状态:已创建但从未使用
可能原因:
建议:
文件中有大量被注释掉的代码:
// <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
// <div
// style={{ width: '100%' }}
// className="grid grid-rows-[1fr] h-0 flex-grow overflow-y-auto"
// >
问题:
建议:移除被注释的代码,保持代码整洁
const onClick = (key: string) => {
onMenuClick?.(key);
};
当前:函数名为 onClick
,但实际是处理菜单点击
改进建议:更明确的命名,如 handleMenuClick
NavMenu 非常简单,几乎只是一个布局包装器。
思考:
保留的理由:
NavMenu 用于大屏幕(xl 和 lg 尺寸)的侧边栏导航:
// 在 BasicLayout 中
<Col xl={2} lg={2} md={0} sm={0} xs={0}>
<NavMenu onMenuClick={handleMenuClick} />
</Col>
响应式策略:
由于 NavMenu 非常简单,可以考虑简化:
<BusinessZone onMenuClick={onMenuClick} />
<SystemZone onMenuClick={onMenuClick} />
直接传递 onMenuClick
,不需要中间的 onClick
函数。
const NavMenu: React.FC<NavMenuProps> = ({ onMenuClick }) => {
return (
<Flex vertical className="h-full">
<BusinessZone onMenuClick={onMenuClick} />
<SystemZone onMenuClick={onMenuClick} />
</Flex>
);
};
更加简洁,除非确实需要 ref。
src/layouts/BasicLayout.tsx
:使用 NavMenu 的父组件src/layouts/BusinessZone.tsx
:业务功能区子组件src/layouts/SystemZone.tsx
:系统功能区子组件src/states/BusinessFlowSlice.ts
:业务流程状态管理(最终接收菜单点击事件)