user13286
user13286

Reputation: 3075

React tabbed content based on dynamic data

I am attempting to build out some tabbed content based on this tutorial. When I set up my app exactly like the tutorial, everything works great. The problem is I want to build these tabs with dynamic content, and sometimes there will not be any content for one or more of the tabs, so I am attempting to generate the tabs based on the data coming in.

Here is what I have attempted:

let tab1 = "Tab 1";
let tab2 = "Tab 2";
let tab3 = false;
let tab4 = "Tab 4";

class Gallery extends Component {
  render() {
    let tabs;

    if (tab1) {
      tabs += (
        <div label="Gator">
          See ya later, <em>Alligator</em>!
        </div>
      );
    }
    if (tab2) {
      tabs += (
        <div label="Croc">
          After 'while, <em>Crocodile</em>!
        </div>
      );
    }
    if (tab3) {
      tabs += (
        <div label="Sarcosuchus">
          Nothing to see here, this tab is <em>extinct</em>!
        </div>
      );
    }
    if (tab4) {
      tabs += (
        <div label="Gator">
          See ya later, <em>Alligator</em>!
        </div>
      );
    }
    return (
      // THIS WORKS
      <Tabs>
        <div label="Gator">
          See ya later, <em>Alligator</em>!
        </div>
        <div label="Croc">
          After 'while, <em>Crocodile</em>!
        </div>
        <div label="Sarcosuchus">
          Nothing to see here, this tab is <em>extinct</em>!
        </div>
      </Tabs>

      // THIS DOESN'T
      // <Tabs>
      //   {tabs}
      // </Tabs>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Gallery />, rootElement);

If you comment out the hardcoded child divs within the Tabs component and uncomment the one where I am using the tabs variable, you can see that there is an error. The error is TypeError: Cannot read property 'label' of undefined on line 15 of Tabs/index.js so it would appear that the children aren't being rendered before the activeTab state is being set. Maybe I am going about this all wrong anyway. Is there a better way to dynamically populate these tabs?

CodeSandbox here

Note that in my actual implementation, the tab1/2/3 is actually JSON, I just hardcoded them as variables for this question.

Upvotes: 1

Views: 1543

Answers (1)

0DDC0
0DDC0

Reputation: 5189

You are expecting your children to be an "array" therefore just concatenating JSX won't do.

You need to create an array with those JSX elements and pass in as children

class Gallery extends Component {
  render() {
    let tabs = [];

    if (tab1) {
      tabs.push(
        <div label="Gator">
          See ya later, <em>Alligator</em>!
        </div>
      );
    }
    if (tab2) {
      tabs.push(
        <div label="Croc">
          After 'while, <em>Crocodile</em>!
        </div>
      );
    }
    if (tab3) {
      tabs.push(
        <div label="Sarcosuchus">
          Nothing to see here, this tab is <em>extinct</em>!
        </div>
      );
    }
    if (tab4) {
      tabs.push(
        <div label="Gator">
          See ya later, <em>Alligator</em>!
        </div>
      );
    }
    return (
      // THIS WORKS
      // <Tabs>
      //   <div label="Gator">
      //     See ya later, <em>Alligator</em>!
      //   </div>
      //   <div label="Croc">
      //     After 'while, <em>Crocodile</em>!
      //   </div>
      //   <div label="Sarcosuchus">
      //     Nothing to see here, this tab is <em>extinct</em>!
      //   </div>
      // </Tabs>

      // THIS DOESN'T
      <Tabs>{tabs}</Tabs>
    );
  }
}

Working sandbox --> https://codesandbox.io/s/amazing-sky-hezzy

Upvotes: 1

Related Questions