Reputation: 4575
I have a React HOC in TypeScript, but it doesn't seem to work when I call it from within a TSX Component render
method. Here's an example:
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);
I'm calling this from a parent JSX file like this:
public render(): JSX.Element {
return (
<div>
Test #1: <HelloWorldComponent/>
Test #2: <HelloWorldComponentWithRedText />
Test #3: { withRedText(<HelloWorldComponent />) }
</div>
)
}
The first and second tests work as expected---the text is red in the second one. But the third line renders nothing. I expected the second and third lines to be the same.
When I step through it with the debugger, the argument to Test #2 is a Component of type HelloWorldComponent
, but Test #3 is seeing a Component = Object {$$typeof: Symbol(react.element), ...}
.
Is there a way to dynamically wrap a Component with syntax like { withRedText(<HelloWorldComponent />) }
from within the JSX/TSX file?
(TypeScript 2.1.4 & React 15.4.0)
Upvotes: 3
Views: 1793
Reputation: 58362
I don't think that you can invoke a HOC directly / implicitly from JSX. Thinking about the implementation of JSX and how HOCs work, I don't think it would be good for performance: every time the component re-renders, it calls the HOC function again, re-creates the wrapped component class, then invokes it.
You can often get a similar effect, though, by creating a component that takes another component as a parameter:
const WithRedText = ({component: Component, children, ...props}) => (
<div style={{color: "red"}}>
<Component {...props}>{children}</Component>
</div>
);
(I'm passing component
as lowercase, because that seems to be the convention for props, but within WithRedText
, I uppercase it, because that's how JSX identifies custom components as opposed to HTML tags.)
Then, to use it:
ReactDOM.render(
<div className="container">
<WithRedText component={HelloWorldComponent} />
</div>,
);
See http://codepen.io/joshkel/pen/MJGLOQ.
Upvotes: 2
Reputation: 11976
That is because in test #3 you pass it an instance: <HelloWorldComponent />
, instead of the type/class HelloWorldComponent
. The JSX gets transpiled to what amounts to a lot of object instantiation boilerplate.
Upvotes: 1