简体   繁体   中英

Can I call HOC directly from within JSX / TSX in React?

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)

Here it is on CodePen

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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM