matrimcauthon0514
matrimcauthon0514

Reputation: 35

Dynamically rendering react components from string array

Running into an issue rendering components dynamically as the come off the CMS in the react code.

Having no problem getting & parsing the variable names into an array to be utilized in the actual rendering - but receiving errors here no matter the method I'm using:

Which clearly shows I'm using caps :)

import React, {
  Component
} from 'react';
import {
  createClient
} from 'contentful';
import CtaBlock from './CTABlock';
import DeviceList from './DeviceList';

class HomeContainer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      pageCont: [],
      entries: []
    };
  }

  componentDidMount() {
    const client = createClient({
      // This is the space ID. A space is like a project folder in Contentful terms
      space: '...',
      // This is the access token for this space. Normally you get both ID and the token in the Contentful web app
      accessToken: '...'
    });

    client.getEntries({
      'sys.id': '5stYSyaM8gkiq0iOmsOyKQ'
    }).then(response => {
      this.setState({
        mainCont: response
      });
    });
  }

  getEntries = pageCont => {
    var linkedEntries = pageCont.includes.Entry;
    console.log(linkedEntries);

    return linkedEntries;
  };

  render() {
    var formattedComponents = [];
    var renderedComponents = [];

    if (this.state.mainCont) {
      //getting the type of component from the Contetful API (String)
      var componentList = this.getEntries(this.state.mainCont).map(entries => entries.sys.contentType.sys.id);

      //converting the component names to upper case 
      formattedComponents = componentList.map(comps => comps.charAt(0).toUpperCase() + comps.slice(1));

      renderedComponents = formattedComponents.map(MyComponent => {
        return <MyComponent / >
      });
    }

    return ( 
      <div>
        <h1> Dynamically Generated Components Div </h1> 
        {renderedComponents} 
      </div>
    );
  }
}

export default HomeContainer;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Appreciate any insight! 

Upvotes: 2

Views: 4061

Answers (1)

Leif Marcus
Leif Marcus

Reputation: 623

When I understand you right, what you want to archive is, to map a string key to a certain component, right?

So that entries.sys.contentType.sys.id contains a string like "ctaBlock"or "deviceList"?

I would suggest using a map as follows:

import CtaBlock from './CTABlock';
import DeviceList from './DeviceList';
import FallbackComponent from './FallbackComponent';
const keyMap = {
    ctaBlock : CtaBlock,
    deviceList : DeviceList,
    default: FallbackComponent,
};
...
componentList.map( entries => {
    const key = entries.sys.contentType.sys.id;
    const Component = keyMap[ key ] || keyMap.default;
    return <Component />;
} );

See an example on: https://jsfiddle.net/v7do62hL/2/

Upvotes: 2

Related Questions