我可以在 React 的 JSX / TSX 中直接调用 HOC 吗?

Posted

技术标签:

【中文标题】我可以在 React 的 JSX / TSX 中直接调用 HOC 吗?【英文标题】:Can I call HOC directly from within JSX / TSX in React? 【发布时间】:2017-06-21 09:48:52 【问题描述】:

我在 TypeScript 中有一个 React HOC,但是当我从 TSX 组件 render 方法中调用它时,它似乎不起作用。这是一个例子:

export class HelloWorldComponent extends React.Component<, > 
    public render(): JSX.Element 
        return <div>Hello, world!</div>;
    


export const withRedText = (Component) => 
    return class WithRedComponent extends React.Component<, > 
        public render(): JSX.Element                 
            return (
                <div style=color: "red">
                    <Component ...this.props />
                </div>
            );
        
    ;
; 

export const HelloWorldComponentWithRedText = withRedText(HelloWorldComponent);

我从这样的父 JSX 文件中调用它:

public render(): JSX.Element 
    return (
       <div>
           Test #1: <HelloWorldComponent/>
           Test #2: <HelloWorldComponentWithRedText />
           Test #3:  withRedText(<HelloWorldComponent />) 
       </div>
    )

第一个和第二个测试按预期工作——第二个测试中的文本是红色的。但是第三行什么也不渲染。我预计第二行和第三行是相同的。

当我使用调试器单步调试时,Test #2 的参数是 HelloWorldComponent 类型的组件,但 Test #3 看到的是 Component = Object $$typeof: Symbol(react.element), ...

有没有办法在 JSX/TSX 文件中使用 withRedText(&lt;HelloWorldComponent /&gt;) 之类的语法动态包装组件?

(TypeScript 2.1.4 和 React 15.4.0)

Here it is on CodePen

【问题讨论】:

这是一个 javascript 版本:codepen.io/mikebridge/pen/mRLvRd 【参考方案1】:

我认为您不能直接/隐式地从 JSX 调用 HOC。考虑 JSX 的实现以及 HOC 的工作方式,我认为这对性能没有好处:每次组件重新渲染时,它都会再次调用 HOC 函数,重新创建包装的组件类,然后调用它。

不过,您通常可以通过创建一个将另一个组件作为参数的组件来获得类似的效果:

const WithRedText = (component: Component, children, ...props) => (
    <div style=color: "red">
      <Component ...props>children</Component>
    </div>
);

(我将 component 传递为小写,因为这似乎是 props 的约定,但在 WithRedText 中,我将其大写,因为这是 JSX 识别自定义组件而不是 html 标记的方式。)

然后,使用它:

ReactDOM.render(
    <div className="container">
        <WithRedText component=HelloWorldComponent />
    </div>,
);

见http://codepen.io/joshkel/pen/MJGLOQ。

【讨论】:

好的,有道理,谢谢。我最终想知道是否可以动态堆叠它们,例如withFeatureOne(withFeatureTwo(&lt;HelloWorldComponent /&gt;)) 但也许这只能静态工作。 在考虑了您的回答后,我意识到我问错了问题。我不能像我想的那样调用 HOC,但我仍然可以使用 React.CreateComponent() 获得不错的语法。我可以使用像 export const createComponent = (component, ...args) =&gt; React.createElement(component, args); 这样的辅助函数来清理它,然后像这样从 JSX 调用它:createComponent(withRedText(HelloWorldComponent))。我可以尽可能多地链接它们,而且语法并不难看。【参考方案2】:

这是因为在测试#3 中你传递了一个实例:&lt;HelloWorldComponent /&gt;,而不是类型/类HelloWorldComponent。 JSX 被转译成大量的对象实例化样板文件。

【讨论】:

以上是关于我可以在 React 的 JSX / TSX 中直接调用 HOC 吗?的主要内容,如果未能解决你的问题,请参考以下文章

React-native:如何在 React-native 中使用(和翻译)带有 jsx 的 typescript .tsx 文件?

React JSX / TSX:使用 Emotion 导入/导出多个模块(主题对象)

在 tsx 编译错误中导入 jsx 文件

TSX 文件中无法识别 React.js 代码(VS 2015 Update 1 RC)

TSX/JSX 项目中的可选 JSX 道具

使用 Typescript(TSX 文件)将道具传递给 React 中的子组件