背景
现在Hooks编程那么火,但是还是避免不了在写业务的时候用到Class-Component,利弊啥的这里的就不说了,不是我要说的重点。React官方文档给Hooks打上标识是只能在Function-Component中使用,这是由于状态管理机制的限制。难道Hooks就真的与Class无缘了吗?我觉得未必。。。。。
一次,我想解决Class-Component中函数调用过程的事件函数预传参的问题。以前最简单的做法就是使用bind函数直接绑定一个或多个预设参数,这个方法非常有效也挺好用。但是觉得很不优雅,并且每次 bind 在render 过程中都会创建一个新的函数,作为处女座的我怎么能忍受??
提问:函数组件不就是个函数吗?Class上不会刻意挂载无穷尽的函数吗?为啥不能把函数组件直接声明到Class上呢?
于是突发灵感,在Class成员方法上直接声明一个箭头函数,Class组件不就能用Hooks了吗?顿时感觉整个世界都清爽了很多。
实现
直接上代码:
interface ICompProps {
list: Array<Pick<ICSFCProps, "label" | "value">>;
onSelectChange(idx: number, value: any): void;
}
interface ICSFCProps {
idx: number;
value: any;
label: any;
}
export class Comp extends PureComponent<ICompProps> {
SFC = ({ idx, value, label }: ICSFCProps) => {
const { onSelectChange } = this.props;
// 通过hooks去缓存函数,而非每次都去创建一个新的函数
const onChange = useCallback(() => {
// 直接调用class接收到的props;
onSelectChange(idx, value);
}, [idx, value]);
return (
<Checkbox value={value} onChang={onChange}>
{label}
</Checkbox>
);
};
render() {
const { list } = this.props;
return (
<div>
{list.map((it, idx) => {
return <this.SFC key={idx} idx={idx} {...it} />;
})}
</div>
);
}
}
修改前的代码:
export class Comp extends PureComponent<ICompProps> {
render() {
const { list, onSelectChange } = this.props;
return (
<div>
{list.map(({ value, label }, idx) => {
return (
<Checkbox value={value} onChang={onSelectChange.bind(null, idx, value)}>
{label}
</Checkbox>
);
})}
</div>
);
}
}
看着修改前的代码那么少,你可能会说:同样的功能,你用了两倍的代码量去实现,你是不是傻呀?
但是,我要告诉你的是,代码量少不代表性能就一定高。React函数式编程的的理想境界就是让UI和State进行强分离,虽然代码量上会有一定的增加,但是,带来的性能提升确实非常可观的,并且,逻辑上的解耦和在后续代码维护中起到的作用也是不容忽视的。扯远了。。。
总结
以上只是一个在Class组件中调用Hooks的示例,当然场景不一定是这样的。但是在很多时候我觉得这样的场景也不会少。—— 我把这种方式叫做【寄生式函数组件】
例如你有很多自定义的Hooks,有些组件又不得不选择Class去实现功能,但Hooks里面的状态管理我又不想再Class里面再写一次的情况下,你就可以考虑一下使用这种方式来调用你的Hooks。爽的一匹~
当然这种方式的缺点还是有的:
- 因为你定义的函数组件是在Class属性上的,组件里面嵌套组件感觉有点怪怪的,可能对后续的维护带来一些小麻烦。
- 由于定义的函数组件是寄生在Class上的,那它就可以访问其宿主Class的所有内置属性、方法、props、stated等一切可访问的数据,因此一定的组件数据管理上的风险。
如果有同学用过这样的方式来进行开发,有什么心得或遇到的坑,欢饮一起讨论~