Brent Anderson
Brent Anderson

Reputation: 81

React help switching between tabs

I need some help switching between tabs. I’ve attached an image to help demonstrate what I mean. I’ve tried many different ways to accomplish this, but I’m stuck. Allow me to explain:

image of tabs

I have created a json file that holds these 5 tabs in an array of objects. Each one has an id and a name. I am dynamically creating each tab component by mapping through this array within a parent component (the navbar component). The reason I’m doing it this way is so I can easily add more tabs to my .json file later and it’ll automatically add more tab components, without the need to code it in. I want a dynamic solution, not a static one.

[
  {
    "id": 0,
    "name": "Home"
  },
  {
    "id": 1,
    "name": "About"
  },
  {
    "id": 2,
    "name": "Skills"
  },
  {
    "id": 3,
    "name": "Projects"
  },
  {
    "id": 4,
    "name": "Games"
  }
]
export default class Navigation extends React.Component {
  buildTabs = (tab) => {
    return(
      <Tab
        key={tab.id}
        id={tab.id}
        name={tab.name}
      />
    );
  }

  render() {
    return(
      <div style={style}>
        {TabJSON.map(this.buildTabs)}
      </div>
    );
  }
}

I have tried to set a selected state within the tab component itself, but when I click a new tab, the previous one doesn’t disappear. It will just toggle them on individually, which isn’t what I want. I would like them to toggle selected and then remove that state from the others, just like a tab is supposed to work.

export default class Tab extends React.Component {
  state = {
    selected: this.props.id === 0 ? 'selected' : ''
  }

  tabClicked = (tab) => {
    this.setState({
      selected: 'selected'
    });
  }

  render() {
    return(
      <div
        id={this.props.id}
        className={`tab ${this.state.selected}`}
        onClick={this.tabClicked}
      >{this.props.name}
      </div>
    );
  }
}

I have tried to manage this state from the parent component (the navbar) so I can communicate between the sibling tab components, but I run into another issue. The components all get selected on or off together, instead of independently no matter which one I click.

Sorry for the long message, I hope someone can help me out.

Upvotes: 2

Views: 8508

Answers (1)

Umberto
Umberto

Reputation: 599

Your selected state must be inside a parent Component. For example, you could add a onClick prop function to your Tab:

export default class Tab extends React.Component {

    render() {

      const { id, onClick, selectedTab } = this.props; 

      return (
          <div
              id= {id}
              className = {`tab ${id === selectedTab ? 'selected' : ''}`}
              onClick = {onClick}
            >
                { this.props.name }
            </div>
        );
    }
}

And then control the Selected tab from your parent component (Navigation), passing the current selected Tab for each one, like this:

export default class Navigation extends React.Component {

  state = { 
     selectedTab: 0
  }

  onClickTab = id => () => {
     this.setState({ selectedTab: id });
  }

  buildTabs = (tab) => {
    return(
      <Tab
        key={tab.id}
        id={tab.id}
        name={tab.name}
        onClick={this.onClickTab(tab.id)}
        selectedTab={this.state.selectedTab}
      />
    );
  }

  render() {
    return(
      <div style={style}>
        {TabJSON.map(this.buildTabs)}
      </div>
    );
  }
}

Upvotes: 1

Related Questions