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

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

问题描述:

我在TypeScript中有一个React HOC,但当我从TSX组件render方法中调用它时似乎不起作用。这里有一个例子:我可以直接从React中的JSX/TSX内部调用HOC吗?

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

第一和第二测试按预期工作---文字是在第二个红色。但第三行不会呈现任何内容。我预计第二和第三行是一样的。

当我使用调试器对其进行检查时,测试#2的参数是HelloWorldComponent类型的组件,但测试#3看到Component = Object {$$typeof: Symbol(react.element), ...}

有没有一种方法可以从JSX/TSX文件中动态地包装一个类似{ withRedText(<HelloWorldComponent />) }的语法的组件?

(打字稿2.1.4 &阵营15.4.0)

Here it is on CodePen

+0

这是JavaScript的版本:http://codepen.io/mikebridge/pen/mRLvRd – mikebridge

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

你往往能获得类似的效果,不过,通过创建需要另一个组件作为参数的组件:

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

(我传递component为小写,因为这似乎是惯例。道具,而是内WithRedText,我大写它,因为这是JSX如何确定自定义组件,而不是HTML标签)

然后,要使用它:

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

请参阅http://codepen.io/joshkel/pen/MJGLOQ

+0

好吧,这很有道理,谢谢。我最终想知道是否可以动态地叠加它们,例如'{withFeatureOne(withFeatureTwo())}'但也许这只会静态工作。 – mikebridge

+0

想到你的答案后,我意识到我问的是错误的问题。我不能像我想的那样调用HOC,但我仍然可以使用'React.CreateComponent()'获得体面的语法。我可以用像'export const createComponent =(component,... args)=> React.createElement(component,args)这样的帮助函数清理它;'然后像这样从JSX调用它:'{createComponent(withRedText(HelloWorldComponent ))'。我可以尽可能多地链接它们,并且语法在眼睛上不太难。 – mikebridge

+0

参见:http://codepen.io/mikebridge/pen/jyxjwe – mikebridge

这是因为在试验#3传递给它的实例:代替HelloWorldComponent的类型/类别<HelloWorldComponent />,。 JSX被转化为相当于大量对象实例化样板的东西。