1
votes

I try to adapt this tabs to react. The idea is to add active class for the key clicked with handleclick function

class Tabs extends React.Component {
  constructor(props) {
    super(props);
    this.state = { selected: 0 };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(key, event) {
    event.preventDefault();
    this.setState({
      selected: key
    });
  }
  render() {
    var activeClass = this.state.selected === this.props.key ? "active" : "";
    return (
      <React.Fragment>
        <div class="tab">
          <button
            key="1"
            className={"tablinks" + activeClass}
            onClick={this.handleClick}
          >
            London
          </button>
          <button
            key="2"
            className={"tablinks" + activeClass}
            onClick={this.handleClick}
          >
            Paris
          </button>
          <button
            key="3"
            className={"tablinks" + activeClass}
            onClick={this.handleClick}
          >
            Tokyo
          </button>
        </div>
        <div key="1" className={"tabcontent" + activeClass}>
          <h3>London</h3>
          <p>London is the capital city of England.</p>
        </div>

        <div key="2" className={"tabcontent" + activeClass}>
          <h3>Paris</h3>
          <p>Paris is the capital of France.</p>
        </div>

        <div key="3" className={"tabcontent" + activeClass}>
          <h3>Tokyo</h3>
          <p>Tokyo is the capital of Japan.</p>
        </div>
      </React.Fragment>
    );
  }
}

ReactDOM.render(<Tabs />, document.querySelector(".container"));

but I get two errors:

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of Tabs.

and

Uncaught Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Check the render method of Tabs.

here is the jsfiddle link

2

2 Answers

1
votes

In your Fiddle it is not working because the use of React.Fragment.

Anyway, it won't work even with previous corrections because this.props.key does not refer to the good variable.

Try this

class Tabs extends React.Component {
    constructor(props) {
    super(props);
    this.state = { selected: '1' };
    this.handleClick = this.handleClick.bind(this);
    }

     handleClick (key) {
        this.setState({
            selected: key
        });
    }

    isActive (key) {
        return this.state.selected === key ? 'active' : ''
    }

    render() {
    var activeClass = (this.state.selected === this.props.key ? 'active' : '');
      return (
  <div>
   <div class="tab"> 
    <button className={'tablinks'+ activeClass} onClick={()=>this.handleClick("1")}>London</button>
      <button  className={'tablinks'+ activeClass} onClick={()=>this.handleClick("2")}>Paris</button>
      <button  className={'tablinks'+ activeClass} onClick={()=>this.handleClick("3")}>Tokyo</button>
    </div>
   <div key='1' className={'tabcontent'+ this.isActive('1')}>
    <h3>London</h3>
    <p>London is the capital city of England.</p>
  </div>

  <div key='2' className={'tabcontent'+ this.isActive('2')}>
    <h3>Paris</h3>
    <p>Paris is the capital of France.</p> 
  </div>

  <div key='3' className={'tabcontent'+ this.isActive('3')}>
    <h3>Tokyo</h3>
    <p>Tokyo is the capital of Japan.</p>
  </div>
  </div>
  );
    }
  }
  ReactDOM.render(<Tabs />, document.querySelector('.container'));
1
votes

The onClick handler handleClick will be passed the event as first argument, not the key. If you want to send the key to the function, you could create an inline function calling handleClick with your desired argument.

You are also using an old version of React in your fiddle that doesn't have React.Fragment that was introduced in React 16, and the class prop on your topmost div element should be className.

Example

class Tabs extends React.Component {
  state = { selected: 0 };

  handleClick = key => {
    this.setState({
      selected: key
    });
  };

  render() {
    var activeClass = this.state.selected === this.props.key ? " active" : "";
    return (
      <React.Fragment>
        <div className="tab">
          <button
            key="1"
            className={"tablinks" + activeClass}
            onClick={() => this.handleClick(1)}
          >
            London
          </button>
          <button
            key="2"
            className={"tablinks" + activeClass}
            onClick={() => this.handleClick(2)}
          >
            Paris
          </button>
          <button
            key="3"
            className={"tablinks" + activeClass}
            onClick={() => this.handleClick(3)}
          >
            Tokyo
          </button>
        </div>
        <div className={"tabcontent" + activeClass}>
          <h3>London</h3>
          <p>London is the capital city of England.</p>
        </div>

        <div className={"tabcontent" + activeClass}>
          <h3>Paris</h3>
          <p>Paris is the capital of France.</p>
        </div>

        <div className={"tabcontent" + activeClass}>
          <h3>Tokyo</h3>
          <p>Tokyo is the capital of Japan.</p>
        </div>
      </React.Fragment>
    );
  }
}