谁说React-Hooks不能在Class-Comp中使用?

4,824 阅读3分钟

背景

现在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等一切可访问的数据,因此一定的组件数据管理上的风险。

如果有同学用过这样的方式来进行开发,有什么心得或遇到的坑,欢饮一起讨论~