React JS – How does 2 separated components able to receive 1 same state?

I am a beginner in using the React JS framework. Based on the official React JS documentation, an example is given for changing the state of a component that has a connected hierarchy. But in my case this time I split the components for Header and Main separately.

index.js

ReactDOM.render(
  <React.StrictMode>
    <Header />
    <Main />
  </React.StrictMode>,
  document.getElementById('root')
);

In the Header component I also have another sub component that functions to activate / deactivate the sidebar which is also a sub menu for the Main component.

Header.js

import { BtnSidebarOnClick } from './Sidebar';

const Header = () => {
  return (
    <header className="header">
      <div className="header__logo">
        <BtnSidebarOnClick />
        <div className="header__logo_img">
          <a className="link"
            href="/">
            <img src=""
              alt="Schedule App" />
          </a>
        </div>
      </div>
      <nav className="header__nav">
        ...
      </nav>
    </header>
  );
}

export default Header;

Main.js

import { Sidebar } from './Sidebar';

const Main = () => {
  return (
    <main className="main">
      <Sidebar />
      <div className="main__content">
        ...
      </div>
    </main>
  );
}

export default Main;

Notice that the BtnSidebarOnClick and Sidebar components are not connected. In my case, this time I want to make the Sidebar component accept state to detect whether the button contained in the BtnSidebarOnClick component is clicked / not.

Sidebar.js

class BtnSidebarOnClick extends React.Component {
  constructor(props) {
    super(props);
    this.state = { onClick: false };
  }

  handleClick() {
    this.setState(state => ({ onClick: !state.onClick }));
  }

  render() {
    return (
      <div className="header__logo_btn">
        <div className="button button--hover button--focus" 
          role="button"
          tabIndex="0"
          onClick={this.handleClick.bind(this)}>
          <i className="material-icons">menu</i>
        </div>
      </div>
    );
  }
}

const Sidebar = () => {
  return (
    <div className="main__sidebar"> {/* set style if BtnSidebarOnClick clicked */}
      <div className="main__sidebar_menu">
        
        <div className="tag-link">
          <a className="link link--hover link--focus link--active"
            href="/">
              <i className="material-icons">insert_drive_file</i>
              <span className="link-title">Files</span>
          </a>
        </div>
      
      </div>
    </div>
  );
}

export { Sidebar, BtnSidebarOnClick };

So how do you set these two components to receive the same state?

Answer

TLDR; You should pull out the button state into the parent and pass it into the children component.

By the way, it is a common way to have file App.js for your main Application file. In your case, it should be like this:

index.js

import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

App.js

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isClicked: false };
  }

  handleClick() {
    this.setState(state => ({ isClicked: !state.isClicked }));
  }

  render() {
    return (
      <div>
        <Header onClick={this.handleClick} /> // --> notice
        <Main isClicked={this.state.isClicked} /> // --> notice
      </div>
    )
  }
}

Header.js

import BtnSidebar from './BtnSidebar';

const Header = (props) => {
  return (
    <header className="header">
      <div className="header__logo">
        <BtnSidebar onClick={props.onClick} /> // --> notice
        <div className="header__logo_img">
          <a className="link"
            href="/">
            <img src=""
              alt="Schedule App" />
          </a>
        </div>
      </div>
      <nav className="header__nav">
        ...
      </nav>
    </header>
  );
}

Main.js

import Sidebar from './Sidebar';

const Main = (props) => {
  return (
    <main className="main">
      <Sidebar isClicked={props.isClicked} /> // --> notice
      <div className="main__content">
        ...
      </div>
    </main>
  );
}

BtnSidebar.js

const BtnSidebar = (props) => {
  return (
    <div className="header__logo_btn">
      <div className="button button--hover button--focus" 
        role="button"
        tabIndex="0"
        onClick={props.onClick} // --> notice
      >
        <i className="material-icons">menu</i>
      </div>
    </div>
  );
}

Sidebar.js

const Sidebar = (props) => {
  return (
    <div
      className={
        props.isClicked ? 'main__sidebar-clicked' : 'main__sidebar' // --> notice
      }
    >
      <div className="main__sidebar_menu">
        <div className="tag-link">
          <a className="link link--hover link--focus link--active"
            href="/">
              <i className="material-icons">insert_drive_file</i>
              <span className="link-title">Files</span>
          </a>
        </div>
      
      </div>
    </div>
  );
}