浅谈 TypeScript - 高阶组件

1,192 阅读2分钟

HOC 并不是一个很具体的组件,它仅仅是一个在 React 对组件进行重用的设计方法,这种设计方法是由 React 自身的设计思想而必然会产生。具体而言,高阶组件就是一个函数,它接收一个组件做为参数,并返回一个组件,这种设计方法的利用,我们可以在很多开源库中看到,如:redux connect ,它们都做为一个高阶组件而存在。

那么在 TypeScript 的世界中,我们改如何去写一个高阶组件呢?

举一个例子:

我们设计一个高阶组件,它来接收一个 styles 对象,并且传递给你传入的组件,这个 styles 对象定义了高宽背景颜色。 首先,我们写一个 withStyle 函数,它接收一个 StyleRules 类型,并且返回一个范型函数,这个范型函数可以接收任意一个 React 组件。

定义 StyleRules:

interface IStyleRules {
  width?: string;
  height?: string;
  backgroundColor?: string;
}

export type StyleRules = IStyleRules;

然后我们定义一个 AnyComponent:

type AnyComponent<P = any> =
| (new (props: P) => React.Component)
| ((props: P & { children?: React.ReactNode }) => React.ReactElement<any> | null);

这个 AnyComponent 用于范型函数接收参数的类型。

最后,我们定义一个 WithStyle 的函数别名:

type WithStyle = (styles: IStyleRules) => <P extends IStylesProps> (Component: AnyComponent<P>) => AnyComponent<P>;

当然,这里我也定义了一个 IStylesProps 用于简单的范型继承,因为我们会将 styles 当 props 传入给传入的组件:

export const withStyle: WithStyle = (styles: IStyleRules) => (Component: AnyComponent) => {

  class HOC extends React.Component<{}> {
    public styles: IStyleRules;
    constructor(props: {}) {
      super(props);
      this.styles = styles;
    }
    public render() {
      return <Component styles={this.styles} />;
    }
  }

  return HOC;
};

最后,我们该如何使用 withStyle 函数呢?

import * as React from "react";
import { withStyle, StyleRules, IStylesProps } from "./hoc";

const s: StyleRules = {
  width: "100px",
  height: "200px",
  backgroundColor: "#980987",
};

type IHOCProps = IStylesProps;

class HOCComponent extends React.Component<IHOCProps> {
  constructor(props: IHOCProps) {
    super(props);
  }

  public render() {
    // console.log(this.props);
    return (
      <div style={this.props.styles}>...</div>
    );
  }
}

export default withStyle(s)(HOCComponent);

当然我们的这个案例中是一个非常简单的高阶组件,正常情况下,你应该要处理好容器组件中的生命周期,这些会有一些额外的事情。这个案例很好的利用了高阶组件这样的设计方法,完成了它想要的结果。