如何用 HOC 包装每个导出的组件?

How to wrap every exported comopnent with HOC?

我需要向我的 React 函数组件的 ALL 添加添加 [data-test-id] 属性的可能性以进行测试。为了实现这一点,我创建了 withTestId() HOC,它将可选的属性 testId 添加到包装的组件中,当它被定义时,它将 [data-test-id] 添加到最终的 HTML.

所以当我像这样定义组件时:

<ExampleComponent testId="example" />

它returns:

<div data-test-id="example" />

我遇到的唯一问题是将它应用于每个组件,而无需将它单独包装在每个组件中。所以不要写这样的代码:

function ExampleComponent() { ... }

export default withTestId(ExampleComponent)

我想将所有导出内容打包到我的 index.ts 文件中,现在看起来像这样:

export { default as ExampleComponent } from "./ExampleComponent";
export { default as ExampleComponent2 } from "./ExampleComponent2";
...

我怎样才能做到这一点?

我看到了两种方法;一种动态方式,使您的库的用户代码更加复杂。您可以轻松地更改实现,另一个具有更多样板代码的实现,保持用户代码不变。

我没有测试他们在打包代码时关于 tree-shaking 的行为。

在用户代码中使用析构

这允许在您的主要组件导出文件中添加/删除内容,而不必担心库中的其他样板文件。可以轻松切换高阶组件 on/off。一个警告:用户代码需要使用解构来检索组件。

您的新 index.ts 文件看起来像这样,而我在同一目录中调用了您之前的 index.ts 文件 components.ts

import * as RegularComponents from "./components";
import withTestId from "./with-test-id";

const WithTestIdComponents = Object
  .keys(RegularComponents)
  .reduce((testIdComps, key) => {
    return {
      ...testIdComps,
      [key]: withTestId(RegularComponents[key])
    };
  }, {});

export default WithTestIdComponents;

要在您的应用程序代码中使用它:

import MyComponents from "./components/tested";
const { Component1, Component2, Component3, Component4 } = MyComponents;

这使用 default 导出使它看起来像是将所有组件放在一个地方,但由于您无法直接解构导出,因此您需要第二步才能从中获取正确的组件。

将样板添加到导出文件

由于库中有一个包含所有导出组件的 index.ts 文件,因此可以 import/rename 每个组件并使用 withTestId 及其名称重新导出它们:

import withTestId from "./with-test-id";
import { default as TmpComponent1 } from "./component1";
import { default as TmpComponent2 } from "./component2";
import { default as TmpComponent3 } from "./component3";
import { default as TmpComponent4 } from "./component4";
export const Component1 = withTestId(TmpComponent1);
export const Component2 = withTestId(TmpComponent2);
export const Component3 = withTestId(TmpComponent3);
export const Component4 = withTestId(TmpComponent4);

这样,进口可以像以前一样使用:

import {
  Component1,
  Component2,
  Component3,
  Component4
} from "./components";

我认为使用 index 文件已经是某种样板,而这种方法增加了它。由于用户代码不需要任何更改,我赞成这种方法。

在我们的一个项目中,每当我们生成新组件时,我们都使用自定义 takeoff 脚本为我们创建这种样板文件。

例子

这里有一个 code sandbox 来查看这两种方法。