Skip to main content

Design UI

tip
  • 尽量是 Headless + Style
  • Headless - 无样式,只有逻辑
    • @radix-ui/react
    • @react-aria
    • @react-stately
    • @headlessui/react
  • Style
    • tailwindcss
    • daisyui

FAQ

Pick vs Select

Picker vs Selector

  • Pick - 挑选
    • 更加随意 - 选择的内容不一定固定
    • 使用场景:
      • 配色器(Color Picker):用户可以从调色板中挑选任意颜色。
      • 图标选择器(Icon Picker):用户可以从图标库中挑选任意图标。
      • 日期选择器(Date Picker):用户可以从日历中挑选任意日期。
  • Select - 选择
    • 更加正式 - 选项固定
    • 使用场景:
      • 下拉菜单(Dropdown):用户从预定义的选项中选择一个。
      • 组合框(Combobox):用户可以从预定义的选项中选择一个或输入新的选项。
      • 单选按钮(Radio):用户从一组单选按钮中选择一个。
      • 复选框(Checkbox):用户可以从一组复选框中选择多个。

React as vs asChild

  • as
    • 替代组件
    • 优势 👍
      • 更支持更复杂的结构
    • 劣势 👎
      • 定义 props 类型相对麻烦,特别是有 forwardRef 的时候
      • forwardRef 不能使用 arrow function 定义 - 无法指定泛型, 只能强制 cast
  • asChild
    • 使用子组件
    • 优势 👍
      • 更简单
      • 更好的类型支持 - 类型处理更简单,不需要考虑实际组件的 props
    • 劣势 👎
      • 多一层结构
      • 无法支持复杂的结构
      • 需要 merge props
    • 参考
export type AsProps<E extends React.ElementType> = Omit<React.ComponentProps<E>, 'as'> & {
as?: E;
};

export type WithAsProps<E extends React.ElementType, P extends {} = {}> = P & AsProps<E>;

//
export type LayoutProps<E extends React.ElementType> = WithAsProps<E>;
const Layout = ({ as, children }) => {
const As = as || 'div';
// 这种时候想要用 asChild 需要将 header 提取为独立组件,使用类似 Layout.Root, Layout.Header 方式来封装更细粒度组件
return (
<As>
<header>...</header>
{children}
</As>
);
};