Search code examples
reactjschildren

Using the React Children code example is not working


"Using the React Children API" code example is not working, tried several syntax options, seems the problem is not quite clear.

http://developingthoughts.co.uk/using-the-react-children-api/

class TabContainer extends React.Component {
    constructor(props) {
        super();
        this.state = {
            currentTabName: props.defaultTab
        }
    }

    setActiveChild = (currentTabName) => {
        this.setState({ currentTabName });
    }

    renderTabMenu = (children) => {
        return React.Children.map(children, child => (
            <TabMenuItem 
                title={child.props.title}
                onClick={() => this.setActiveChild(child.props.name)}
            />
        );
    }

    render() {
        const { children } = this.props;
        const { currentTabName } = this.state;

        const currentTab = React.Children.toArray(children).filter(child => child.props.name === currentTabName);

        return (
            <div>
                {this.renderTabMenu(children)}
                <div>
                    {currentTab}
                </div>
            </div>
        );
    }
}

When I changed code like this, it compiles finally

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";

const TabMenuItem = ({ title, onClick }) => (
    <div onClick={onClick}>
        {title}
    </div>
);

class TabContainer extends React.Component {
  constructor(props) {
    super();
    this.state = {
      currentTabName: props.defaultTab
    }
  }

  setActiveChild = ( currentTabName ) => {
    this.setState({ currentTabName });
  }

  renderTabMenu = ( children ) => {
    return React.Children.map(children, child => (
      <TabMenuItem 
      title={child.props.title}
      onClick={() => this.setActiveChild(child.props.name)}
      />
      ))
  }

  render() {
    const { children } = this.props;
    const { currentTabName } = this.state;

    const currentTab = React.Children.toArray(children).filter(child =>
      child.props.name === currentTabName);

    return (
      <div>
        {this.renderTabMenu(children)}
        <div>
          {currentTab}
        </div>
      </div>
      );
  }
}

ReactDOM.render(<TabContainer />, document.getElementById("root"));

Not quite experienced with JS and React, so my questions:

1) should this.setActiveChild be used as this.props.setActiveChild?

2) renderTabMenu = ( children ) or renderTabMenu = ({ children })

3) how to fill this page with some content? I don't see any physical children actually present =)

4) don't get the point why bloggers put the code with errors or which is difficult to implement, very frustrating for newcomers

5) any general guidance what can be not working in this example are welcome


Solution

  • Using React.Children or this.props.children can be a bit of a level up in your understanding of React and how it works. It'll take a few tries in making a component work but you'll get that aha moment at some point. In a nutshell.

    this.props.children is an array of <Components /> or html tags at the top level.

    For example:

    <MyComponent>
      <h1>The title</h1>         // 1st child
      <header>                   // 2nd child
        <p>paragraph</p>
      </header>
       <p>next parapgraph</p>    // 3rd child
    </MyComponent>
    

    1) should this.setActiveChild be used as this.props.setActiveChild?
    Within the TabContainer any functions specified within it need to be proceeded with this. Within a react class this refers to the class itself, in this case, TabContainer. So using this.setActiveChild(). will call the function within the class. If you don't specify this it will try to look for the function outside of the class.

    renderTabMenu = ( children ) or renderTabMenu = ({ children })
    renderTabMenu is a function which accepts one param children, so call it as you would call it as a normal function renderTabMenu(childeren)

    How to fill this page with some content? I don't see any physical children actually present =)
    Here's where the power of the TabsContainer comes in. Under the hood, things like conditional rendering happen but outside of it in another component you specify the content. Use the following structure to render home, blog, and contact us tabs.

    <TabsContainer defaultTab="home">
      <Tab name="home" title="Home">
        Home Content
      </Tab>
      <Tab name="blog" title="Blog">
        Blog Content
      </Tab>
      <Tab name="contact" title="Contact Us">
        Contact content
      </Tab>
    </TabsContainer>
    

    I know how hard it is to make some examples work especially when you are starting out and are still exploring different concepts that react has to offer. Luckily there's stack overflow :).

    Here's real live example to play around with, visit this CodeSandBox.