LobeHub React 组件约定。在编辑 TSX UI、选择 base-ui 与 @lobehub/ui 或 antd、使用 antd-style 进行样式设计、路由、桌面端变体、布局或组件状态时使用。
React 组件编写指南
样式
| 场景 | 方法 |
|---|---|
| 大多数情况 | createStaticStyles + cssVar.*(零运行时,模块级) |
| 简单的一次性样式 | 内联 style 属性 |
真正动态(JS 颜色函数如 readableColor/chroma) |
createStyles + token — 最后手段 |
组件优先级
src/components— 项目特定的可复用组件@lobehub/ui/base-ui— 无头原语。如果组件在此处,请使用它。不要导入同名的根导出。@lobehub/ui— 更高级别的 / 包装 antd 的组件(仅当 base-ui 没有等效组件时)- antd — 仅当 base-ui 和
@lobehub/ui根导出都没有提供时 - 自定义实现 — 真正的最后手段
如果不确定可用组件,请搜索现有代码或检查 node_modules/@lobehub/ui/es/index.mjs 和 node_modules/@lobehub/ui/es/base-ui/。
@lobehub/ui/base-ui — 始终优先使用这些
| 组件 | 导入 |
|---|---|
Select(+ SelectProps、SelectOption) |
import { Select } from '@lobehub/ui/base-ui'; |
Modal(命令式 API) |
import { createModal, confirmModal, useModalContext, type ModalInstance } from '@lobehub/ui/base-ui'; |
DropdownMenu |
import { DropdownMenu } from '@lobehub/ui/base-ui'; |
ContextMenu |
import { ContextMenu } from '@lobehub/ui/base-ui'; |
Popover |
import { Popover } from '@lobehub/ui/base-ui'; |
ScrollArea |
import { ScrollArea } from '@lobehub/ui/base-ui'; |
Switch |
import { Switch } from '@lobehub/ui/base-ui'; |
Toast |
import { Toast } from '@lobehub/ui/base-ui'; |
FloatingSheet |
import { FloatingSheet } from '@lobehub/ui/base-ui'; |
对于 Modal,请参阅专门的 modal 技能 — 使用命令式 createModal({ content: … }) 模式,而不是传统的 <Modal open … /> 声明式模式。base-ui 有自己的 ModalHost 已挂载在 SPAGlobalProvider 中。
常见错误:
import { Select } from '@lobehub/ui'看起来没问题,但它是基于 antd 的 Select。请使用 base-ui 的 Select。Modal、DropdownMenu等也是如此。
@lobehub/ui 根导出 — 当 base-ui 没有等效组件时使用
| 类别 | 组件 |
|---|---|
| 通用 | ActionIcon、ActionIconGroup、Block、Button、Icon |
| 数据展示 | Avatar、Collapse、Empty、Highlighter、Markdown、Tag、Tooltip |
| 数据输入 | CodeEditor、CopyButton、EditableText、Form、Input、InputPassword、SearchBar、TextArea |
| 反馈 | Alert、Drawer |
| 布局 | Center、DraggablePanel、Flexbox、Grid、Header、MaskShadow |
| 导航 | Burger、Menu、SideNav、Tabs |
加载指示器
不要使用 antd 的 Spin / <Spin />。 使用项目加载器(NeuralNetworkLoading、DotsLoading 等)— 请参阅 ux 技能(“加载视觉”)以获取组件表格及何时使用每种加载器。
状态
当功能组件管理超过 3 个状态(useState/useReducer/派生状态)时,将逻辑提取到自定义 hook 中(例如 useXxx)。保持组件专注于渲染 — hook 持有状态和处理程序,因此逻辑可以在不渲染组件的情况下进行单元测试。
布局
使用 @lobehub/ui 中的 Flexbox 和 Center。请参阅 references/layout-kit.md 获取完整属性和示例。
- 使用
gap而不是margin来设置 flex 子项之间的间距 - 使用
flex={1}填充可用空间 - 嵌套 Flexbox 实现复杂布局;设置
overflow: 'auto'用于可滚动区域
导航
对于 SPA 页面,使用 react-router-dom,而不是 next/link。
// ❌ 错误
import Link from 'next/link';
// ✅ 正确
import { Link, useNavigate } from 'react-router-dom';
从 store 中访问 navigate:useGlobalStore.getState().navigate?.('/settings');
桌面端文件同步规则
具有 .desktop.ts(x) 变体的文件必须同步编辑。不同步会导致 Electron 中出现空白页面。
| 基础文件(Web) | 桌面端文件(Electron) |
|---|---|
desktopRouter.config.tsx |
desktopRouter.config.desktop.tsx |
componentMap.ts |
componentMap.desktop.ts |
编辑任何 .ts/.tsx 后: 在同一目录中搜索 <filename>.desktop.{ts,tsx}。如果找到,应用等效的同步导入更改。
路由架构
| 路由类型 | 用途 | 实现 |
|---|---|---|
| Next.js App Router | 认证外壳 | src/app/spa-auth/(HTML 外壳;请参阅 spa-routes) |
| React Router DOM | 认证页面 | src/routes/auth/(登录、注册、OAuth 等) |
| React Router DOM | 主 SPA | desktopRouter.config.tsx + .desktop.tsx(成对) |
路由工具:
import { dynamicElement, redirectElement, ErrorBoundary } from '@/utils/router';
element: dynamicElement(() => import('./chat'), 'Desktop > Chat');
element: redirectElement('/settings/profile');
errorElement: <ErrorBoundary />;
常见错误
| 错误 | 修复 |
|---|---|
在 SPA 中使用 next/link |
使用 react-router-dom 的 Link |
| 直接使用 antd | 优先使用 @lobehub/ui/base-ui,然后 @lobehub/ui |
使用 antd 的 Spin / <Spin /> 作为加载指示器 |
使用 NeuralNetworkLoading / 项目加载器(请参阅 ux 技能) |
import { Select } from '@lobehub/ui' |
import { Select } from '@lobehub/ui/base-ui' |
import { Modal } from '@lobehub/ui' + <Modal open> 声明式 |
使用 @lobehub/ui/base-ui 的 createModal / confirmModal(请参阅 modal 技能) |
import { DropdownMenu/Popover/Switch } from '@lobehub/ui' |
改为从 @lobehub/ui/base-ui 导入同名组件 |
对静态样式使用 createStyles |
使用 createStaticStyles + cssVar |
只编辑 desktopRouter.config.tsx |
必须同时编辑 .tsx 和 .desktop.tsx |
使用 margin 设置 flex 间距 |
使用 Flexbox 的 gap 属性 |
| 无选择器访问 zustand store | 使用选择器访问 store 数据(请参阅 zustand 技能) |
使用 Flexbox/Text + onClick 构建文本或图标文本操作 |
使用 Button type={'text'} size={'small'},并在需要时添加 icon |






