具有withStyles的JSX元素中的泛型类型参数 [英] Generic type arguments in JSX elements with withStyles

查看:373
本文介绍了具有withStyles的JSX元素中的泛型类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在带有Material-ui的React中,我试图创建一个JSX组件,该组件接受通用参数,并且还使用withStyles HOC来注入我的样式.

In React with material-ui I am trying to create a JSX component that accepts generic parameters and also uses the withStyles HOC to inject my styles.

第一种方法是这样的:

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>> {
      ...
    }
),

但是当尝试使用它时,通用类型会丢失

But when trying to use this, the generic types are lost

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

我唯一能找到的解决方案是将导出文件包装在一个具有通用参数并构造组件的函数中.

The only solution I could find was to wrap the export in a function which takes the generic parameter and constructs the component.

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);
}

尽管这只是在试图解决类型问题,但是这非常荒谬,甚至带来运行时成本.

However this is ridiculously complicated and even comes with runtime cost, although it is only trying to solve problems typings.

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

There has to be a better way to use JSX components with generic parameters and HOCs.

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

This is closely related to the issue here https://github.com/mui-org/material-ui/issues/11921, but there was never satisfying solution and the issue is now closed.

推荐答案

我对问题的思考越多,我就越喜欢

The more I think about the question, the more I like Frank Li's approach. I'd make two modifications: (1) introduce an extra SFC to avoid a cast, and (2) grab the outer props type from the wrapped component C instead of hard-coding it. (If we hard-coded Props<T>, TypeScript would at least check that it is compatible with this.C, but we are at risk of requiring props that this.C doesn't actually require or failing to accept optional props that this.C actually accepts.) It's jaw-dropping that referencing a property type from a type argument in the extends clause works, but it seems to!

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应用程序的上下文中,任何对这种方法的运行时开销的抱怨可能都是胡说八道.当有人提供支持他们的数据时,我会相信他们.

I think any complaints about runtime overhead of this approach are probably nonsense in the context of a whole React application; I'll believe them when someone presents data supporting them.

请注意,Lukas Zech使用SFC的方法非常不同:每次更改外部SFC的属性并再次调用该属性时,都会再次调用withStyles,生成一个wrapper,看起来像一个全新的React组件类型,因此React会丢弃旧的wrapper实例,并创建一个新的内部BaseFormCard组件.这将具有不良的行为(重置状态),更不用说更大的运行时开销了. (我实际上尚未对此进行测试,因此,如果我缺少某些东西,请告诉我.)

Note that Lukas Zech's approach using an SFC is very different: every time the props to the outer SFC change and it is called again, withStyles is called again, generating a wrapper that looks to React like a whole new component type, so React throws away the old wrapper instance and a new inner BaseFormCard component gets created. This would have undesirable behavior (resetting state), not to mention greater runtime overhead. (I haven't actually tested this, so let me know if I'm missing something.)

这篇关于具有withStyles的JSX元素中的泛型类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆