<div id="root"></div>
class App extends React.Component {
  initialState = { on: false };

  constructor(props) {
    super(props);
    this.state = this.initialState;

    this.handleToggle = this.handleToggle.bind(this);
  }

  handleToggle = () => {
    this.setState(({ on }) => ({
      on: !on,
    }));
  };

  render() {
    const { on } = this.state;

    return (
      <div>
        <Toggle />

        <Toggle on={on} onToggle={this.handleToggle} />
      </div>
    );
  }
}

class Toggle extends React.Component {
  initialState = { timesClicked: 0, on: false };

  constructor(props) {
    super(props);
    this.state = this.initialState;

    this.isPropsControlled = this.isPropsControlled.bind(this);
    this.toggle = this.toggle.bind(this);
  }

  isPropsControlled() {
    return this.props.on !== undefined;
  }

  toggle() {
    if (this.isPropsControlled()) {
      this.props.onToggle(!this.props.on);
    } else {
      this.setState(({ on }) => ({ on: !on }));
    }
  }

  render() {
    let on = this.isPropsControlled() ? this.props.on : this.state.on;
    return (
      <div>
        <p>
          {this.isPropsControlled() ? "Controlled" : "Uncontrolled"} Component
        </p>
        <button type="button" onClick={this.toggle}>
          {on ? "on" : "off"}
        </button>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js