react

react

热门

LobeHub React 组件约定。在编辑 TSX UI、选择 base-ui 与 @lobehub/ui 或 antd、使用 antd-style 进行样式设计、路由、桌面端变体、布局或组件状态时使用。

8.1万Star
1.6万Fork
更新于 2026/7/25
SKILL.md
readonly只读
name
react
description

LobeHub React 组件约定。在编辑 TSX UI、选择 base-ui 与 @lobehub/ui 或 antd、使用 antd-style 进行样式设计、路由、桌面端变体、布局或组件状态时使用。

React 组件编写指南

样式

场景 方法
大多数情况 createStaticStyles + cssVar.*(零运行时,模块级)
简单的一次性样式 内联 style 属性
真正动态(JS 颜色函数如 readableColor/chroma createStyles + token最后手段

组件优先级

  1. src/components — 项目特定的可复用组件
  2. @lobehub/ui/base-ui — 无头原语。如果组件在此处,请使用它。不要导入同名的根导出。
  3. @lobehub/ui — 更高级别的 / 包装 antd 的组件(仅当 base-ui 没有等效组件时)
  4. antd — 仅当 base-ui 和 @lobehub/ui 根导出都没有提供时
  5. 自定义实现 — 真正的最后手段

如果不确定可用组件,请搜索现有代码或检查 node_modules/@lobehub/ui/es/index.mjsnode_modules/@lobehub/ui/es/base-ui/

@lobehub/ui/base-ui — 始终优先使用这些

组件 导入
Select(+ SelectPropsSelectOption 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。ModalDropdownMenu 等也是如此。

@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 /> 使用项目加载器(NeuralNetworkLoadingDotsLoading 等)— 请参阅 ux 技能(“加载视觉”)以获取组件表格及何时使用每种加载器。

状态

当功能组件管理超过 3 个状态(useState/useReducer/派生状态)时,将逻辑提取到自定义 hook 中(例如 useXxx)。保持组件专注于渲染 — hook 持有状态和处理程序,因此逻辑可以在不渲染组件的情况下进行单元测试。

布局

使用 @lobehub/ui 中的 FlexboxCenter。请参阅 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-domLink
直接使用 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-uicreateModal / 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