React 基础组件规范
组件的定义方式以实现最大程度上的可组合为优先。
基础结构
对于一个最小的可组合组件来说,大致结构如下:
1 2 3 4 5 6 7 8
| interface StepperProps { current: number; }
const Stepper: FC<StepperProps> = (props) => { const { current } = props; return <div>{current}</div>; };
|
组件拆分与组织
对于大型组件需要拆分,namespace 的组织方法已经随着 RSC 兴起被逐步废弃,组件的组织方法只能是这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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,最大程度上保证调用处的方便。
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| 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 left-0 top-0 flex flex-col gap-2"></div> </PreviewContainer> ); };
|