我们以一个Button组件为例。尝试从设计到实现一个React组件。
按钮的设计
轮廓线(按钮的边框)
主要的作用就是按钮与背景色相近的时候让按钮更加的明显。
成像效果不好的显示器,显示效果会有偏差。加上轮廓线确保显示。
类型检测
静态类型检测是写组件必不可少的。一方面是在开发时避免类型问题,它还可以通过IDE的智能提醒方便使用组件的开发者。将使用Typescript对组件进行类型检测声明。
Props声明
首先是Props声明,Props声明我们用组件名后面跟Props
的形式来定义接口名称,并将它导出。
1 | export interface BaseButtonProps { |
在定义props的时候,我们要保持接口小,props数量要少。
组件声明
在组件使用中,应该无状态组件>有状态组件>Class组件。尤其是在hook出现后,函数组件被React大肆推广。
函数组件
我们用FC来声明函数组件,FC就是FunctionComponent的缩写,我们可以通过源码看到,它的props默认定义了children。1
2
3const ButtonBase:FC<BaseButtonProps> = props => {
return <div>{props.children}</div>
}
然后将这个组件导出1
export default Button;
但是在之前FC类型来声明函数组件时并不能完美支持propsDefault(现在已经解决)。
一般用解构赋值的默认值来代替propsDefault
1 | const BaseButton:FC<BaseButtonProps> = props => { |
也有直接使用普通函数来进行组件声明1
2
3
4const BaseButton = (props: BaseButtonProps): JSX.Element => {
const { type = "default" } = props;
return <div>{type}</div>
}
用普通函数来进行组件声明还有以下好处:
- React.FC隐式的提供了一个children props,如果你的组件不需要子组件,用普通函数组件也许是一个很好的选择
支持泛型。例如
1
2
3
4
5
6
7type OptionValue = string | number;
type Option<T extends OptionValue> = {
value: T;
};
const App = <T extends OptionValue>(props: Option<T>): JSX.Element => <div>{props.value}</div>在使用defaultProps不会出错。
【注意】在使用普通函数来进行组件声明的时候,defaultProps的类型和组件本身的props没有关联性,会使得defaultProps无法得到类型约束。比如
1 | interface ButtonProps { |
我们需要改写成这样1
2
3
4
5type Partial<T> = {
[P in keyof T]?: T[P];
};
Button.defaultProps = { name: 'Liam' } as Partial<ButtonProps>