shau-kote
shau-kote

Reputation: 1150

How can I get the JSX elements rendered by a component?

Short version: I have a component type (a class or a function) and props for it. I need to "render" the component to obtain its representation in JSX elements. (I use the quotes because I mean «render into JSX elements» not «render into UI» and I am not sure about the terminology.)

Example:

const Foo = (props) => <div><Bar>{props.x + props.y}</Bar></div>;

// is an equivalent of `const elements = <div><Bar>3</Bar></div>;`
const elements = render2elements(Foo, { x: 1, y: 2 }); 

function render2elements(type, props) { 
    /* what should be here? */ 
}

Long version (for background story enthusiasts, may be skipped imo)

I have a React code whose very simplified version looks like this:

function Baby(props) { 
    /* In fact, it does not even matter what the component renders. */
    /* It is used primarily as a configuration carrier. */
} 
function Mother({ children }) {
    const babies = getAllBabies(React.Children.toArray(children));
    const data = parseData(babies);
    
    return buildView(data);
}

function SomeOtherComponent(props) {
    const { someProps1, someProps2, 
            someProps3, someCondition } = someLogic(props);

    return (
        <Mother>
            <Baby {...someProps1} />
            <Baby {...someProps2} />
            {someCondition ? <Baby {...someProps3} /> : null}
        </Mother>
    );
}

It may be strange but it works. :) Until someone wants to do a little refactoring:

function Stepmother(props) {
    const { someProps1, someProps2, 
            someProps3, someCondition } = someLogic(props);     

    return (
        <>
            <Baby {...someProps1} />
            <Baby {...someProps2} />
            {someCondition ? <Baby {...someProps3} /> : null}
        </>
    );
}

function SomeOtherComponent(props) {
    return <Mother><Stepmother {...props} /></Mother>;
}

Now the Mother receives in its children only a JSX element for the Stepmother and can not parse the JSX elements for the Baby'ies. :(

So we return to my original question: I need to "render" Stepmother and then parse its internal JSX representation. But how can I do this?

P.S. I used functional components for brevity, but of course, all examples could use class components as well.

Thank you.

Upvotes: 1

Views: 644

Answers (1)

paolostyle
paolostyle

Reputation: 1988

Don't do that.

I strongly encourage you to just rethink this solution altogether, ESPECIALLY if

It is used primarily as a configuration carrier.

...but.

So this kinda works however there's a couple of caveats:

  • if a component passed to that function is a class component and has some state, you won't be able to use any of it, in general it will probably cause a ton of issues that I'm not aware of
  • if a component passed is a function component, you can't use any hooks. It will just throw an error at you.
function render2elements(component, props) { 
  if (component.prototype.isReactComponent) {
    return new component(props).render();
  }

  return component(props);
}

So if your "babies" are really simple this technically would work. But you just shouldn't refactor it the way you want and, again, ideally rethink this whole concept.

Upvotes: 2

Related Questions