reactjs - 带有 withStyles 的 JSX 元素中的通用类型参数

标签 reactjs typescript material-ui

在 React with material-ui 中,我尝试创建一个 JSX 组件,它接受通用参数并使用 withStyles HOC 来注入(inject)我的样式。

第一种方法是这样的:

const styles = (theme: Theme) => createStyles({
  card:    {
    ...
  }
});

interface Props<T> {
  prop: keyof T,
  ...
}

type PropsWithStyles<T> = Props<T> & WithStyles<typeof styles>;

export default withStyles(styles)(
    class BaseFormCard<T> extends React.Component<PropsWithStyles<T>> {
      ...
    }
),

但是当尝试使用它时,泛型类型丢失了

<BaseFormCard<MyClass> prop={ /* no typings here */ } />

我能找到的唯一解决方案是将导出包装在一个函数中,该函数采用通用参数并构造组件。

export default function WrappedBaseFormCard<T>(props: Props<T>): ReactElement<Props<T>> {

  const wrapper = withStyles(styles)(
        class BaseFormCard<T> extends React.Component<PropsWithStyles<T>> {
          ...
        }
    ) as any;

  return React.createElement(wrapper, props);
}

然而,这非常复杂,甚至会带来运行时成本,尽管它只是试图解决输入问题。

必须有更好的方法来使用具有通用参数和 HOC 的 JSX 组件。

这与这里的问题密切相关https://github.com/mui-org/material-ui/issues/11921 , 但一直没有令人满意的解决方案,问题现已关闭。

最佳答案

问题越想越喜欢Frank Li's approach .我会做两个修改:(1)引入一个额外的 SFC 以避免强制转换,以及(2)从包装组件中获取外部 Prop 类型 C而不是对其进行硬编码。 (如果我们对 Props<T> 进行硬编码,TypeScript 至少会检查它是否与 this.C 兼容,但我们有可能需要 this.C 实际上不需要或失败的 Prop 接受 this.C 实际接受的可选 Prop 。)从 extends 中的类型参数引用属性类型令人瞠目结舌。子句有效,但它似乎有效!

class WrappedBaseFormCard<T> extends React.Component<
  // Or `PropsOf<WrappedBaseFormCard<T>["C"]>` from @material-ui/core if you don't mind the dependency.
  WrappedBaseFormCard<T>["C"] extends React.ComponentType<infer P> ? P : never,
  {}> {
  private readonly C = withStyles(styles)(
    // JSX.LibraryManagedAttributes handles defaultProps, etc.  If you don't
    // need that, you can use `BaseFormCard<T>["props"]` or hard-code the props type.
    (props: JSX.LibraryManagedAttributes<typeof BaseFormCard, BaseFormCard<T>["props"]>) =>
      <BaseFormCard<T> {...props} />);
  render() {
    return <this.C {...this.props} />;
  }
}

我认为任何关于这种方法的运行时开销的提示在整个 React 应用程序的上下文中都可能是无稽之谈;当有人提供支持他们的数据时,我会相信他们。

请注意,Lukas Zech 使用 SFC 的方法非常不同:每次外部 SFC 的 Prop 发生变化并再次调用时,withStyles再次调用,生成 wrapper在 React 看来就像一个全新的组件类型,所以 React 扔掉了旧的 wrapper实例和一个新的内部 BaseFormCard组件被创建。这会产生不良的行为(重置状态),更不用说更大的运行时开销了。 (我还没有真正测试过这个,所以如果我遗漏了什么,请告诉我。)

关于reactjs - 带有 withStyles 的 JSX 元素中的通用类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52567697/

相关文章:

javascript - typescript ->从Json.net转换字典的内容

css - Material ui 选项卡容器的动态高度

javascript - 试图从弹出窗口的 ul 标签中删除填充

javascript - 在不改变原始数组的情况下过滤 javascript 树

reactjs - 将 "Row Number"添加到 react-admin Datagrid 中的列表组件

css - 位置为 : fixed? 的移动对象的转换

css - 无法修改 Material UI 的 <Dialog> 组件的部分内部样式

javascript - React Native FlatList组件数据在firebase数据调用后不断刷新,无法一致显示Firebase数据

javascript - 是否可以混合使用 TypeScript 和 CoffeeScript?

javascript - 从 Angular 2 升级到 Angular 4.4 时 Angular 路由器问题