Home > OS >  Dynamic React child components not rendering in UI based on JSON Config
Dynamic React child components not rendering in UI based on JSON Config

Time:09-02

I am trying to render React Components based on a JSON response from a CMS system, but I can't seem to render the child item components. Can anyone tell me what I am missing/not understanding here?

Here is my code...

// ComponentRenderer.tsx 
    
export const ComponentsHandler: { [key: string]: any } = {
      test: Test,
    };
        
    export default function ComponentRenderer(config: IBlock): JSX.Element {
          if (typeof ComponentsHandler[config.component] !== 'undefined') {
            return React.createElement(
              ComponentsHandler[config.component],
              {
                key: config.id,
                ...config,
              },
              config.content &&
                (typeof config.content === 'string'
                  ? config.content
                  : config.content.map((c: IBlock) => ComponentRenderer(c)))
            );
          }
          return React.createElement(() => (
            <div>
              Error: Unable to load <strong>{config.component}</strong> component.
            </div>
          ));
        }

Here is the JSON object I am trying to render:

blocks: [
    {
      id: '1',
      component: BlockType.Test,
      content: [],
    },
    {
      id: '2',
      component: BlockType.Test,
      content: [
        {
          id: '3',
          component: BlockType.Test,
          content: [],
        },
        {
          id: '4',
          component: BlockType.Test,
          content: 'this is a string',
        },
      ],
    }
]


export interface IBlock {
  id: string;
  component: BlockType;
  content: IBlock[] | string;
}

export enum BlockType {
  Test = 'test',
  Hero = 'hero',
  Video = 'video',
  Menu = 'menu',
  Navigation = 'navigation',
  Testimonial = 'testimonial',
  Card = 'card',
  CarTile = 'carTile',
  HorizontalScrollSection = 'horizontalScrollSection',
  Div = 'div',
  Section = 'section',
}

Here is the "Test" component I am looking to render in the JSON response

// TestComponent.tsx  
   
export default function Test(props: IBlock) {
      return props.content && <p>{props.id}</p>;
}



// UI HomePage

export default function HomePage() {
  return (
    mockData &&
    mockData.blocks.map((block: IBlock) => (
      <ComponentRenderer {...block} key={block.id}></ComponentRenderer>
    ))
  );
}

I would expect the browser to render

1 2 3 4

But instead, I only get the top-level JSON items.

1 2

CodePudding user response:

You created a really cool react recursive structure. A few days ago I tried to do something similar but gave up... I will use yours as an inspiration.

Check if this changes can help you:

IBlock:

export interface IBlock {
  id: string;
  component: BlockType;
  content: IBlock[] | string;
  children?: React.ReactNode;
}

TestComponent.tsx

export default function Test(props: IBlock) {
  return (
    props.content && (
      <p>
        {props.id} {props.children}
      </p>
    )
  );
}
  • Related