AKR

React 规范

React 基础组件规范

组件的定义方式以实现最大程度上的可组合为优先。

基础结构

对于一个最小的可组合组件来说,大致结构如下:

interface StepperProps {
  current: number;
}

const Stepper: FC<StepperProps> = (props) => {
  const { current } = props;
  return <div>{current}</div>;
};

组件拆分与组织

对于大型组件需要拆分,namespace 的组织方法已经随着 RSC 兴起被逐步废弃,组件的组织方法只能是这样:

const PreviewHeader: FC = ({ title }) => {
    return <div>{title}</div>
}

const PreviewContent: FC = ({ children }) => {
    return <div>{children}</div>
}

const PreviewContainer: FC = ({ header, content, footer }) => {
    return (
        <section>
            <header>{header}</div>
            <main>{content}</div>
        </section>
    )
}

通过 slot 的方式来将组件拆分,最大程度上实现可组合。

转发 DOM 属性

尽量暴露足够多的 props,最大程度上保证调用处的方便。

interface InputProps extends ComponentProps<"input"> {
  label: string;
}

const Input: FC<InputProps> = forwardRef((props, ref) => {
  const { label, ...rest } = props;
  return (
    <label>
      {label}
      <input {...props} ref={ref} />
    </label>
  );
});

样式、布局、结构、功能分离

先阐释概念:

  1. 样式:决定外观的部分
  2. 布局:决定位置的部分
  3. 结构:为组件的组成提供视觉锚定的部分
  4. 功能:决定组件的行为的部分

比如:

// 决定结构
const PreviewContainer: FC = (props) => {
  return (
    <section className={classNames("", className)}>
      <header>{props.header}</header>
      <main>{props.content}</main>
    </section>
  );
};

// 具体的组件,表达样式
const PreviewButton: FC = (props) => {
  return (
    <button className={classNames("", className)} {...props}>
      {props.children}
    </button>
  );
};

const AppPreview: FC = (props) => {
  return (
    <PreviewContainer
      header={
        <PreviewButton
          // 在实际的页面中决定功能
          onClick={() => console.log("hello")}
        >
          hello
        </PreviewButton>
      }
    >
      {/* 在此处决定布局 */}
      <div className="absolute top-0 left-0 flex flex-col gap-2"></div>
    </PreviewContainer>
  );
};