How to send state from Child component to another component in React

Viewed 403

I have a problem with sending state from Child to Parent. After clicking on Menu in Main component I want to change state active and send this active to Sidebar component, because I want to hide/show Sidebar depends on active class from css. It is easy in Vanilla JS but in React I am little confused.

Main:

import Menu from "./Menu";

import "./Styles.css";

import teamsdb from "./teamsdb";

const Main = ({ name }) => {
  
  return (
    <div>
      <Menu />
      <h1>Main</h1>
      <h4>{teamName}</h4>
    </div>
  );
};

Menu:

const Menu = () => {
  const [active, setActive] = useState(false);
  const changeMenu = () => {
    setActive(!active);
  };
  return <button onClick={changeMenu}>Menu</button>;
};

export default Menu;

Sidebar:

const Sidebar = () => {
  const [searchTerm, setSearchTerm] = React.useState("");
  const handleChange = e => {
    setSearchTerm(e.target.value);
    console.log("Search: ", e.target.value);
  };

  return (
    <div className={active ? 'sidebar active' : 'sidebar'}>
      <div className="sidebar__header">
        Header
        <button>Colors</button>
      </div>
      <div className="sidebar__search">
        <input
          type="text"
          placeholder="Search"
          value={searchTerm}
          onChange={handleChange}
        />
      </div>
      <Teams search={searchTerm} />
    </div>
  );
};

App.js

import React from "react";
import "./App.css";
import Sidebar from "./components/Sidebar";
import Main from "./components/Main";

import { BrowserRouter as Router, Switch, Route } from "react-router-dom";    
function App() {
      return (
        <div className="App">
          <div className="app__body">
            <Router>
              <Sidebar />
              <Switch>
                <Route path="/team/:teamId">
                  <Main />
                </Route>
                <Route exact path="/">
                  <Main />
                </Route>
              </Switch>
            </Router>
          </div>
        </div>
      );
    }
2 Answers

You should lift your state up the first common ancestor component, in your case: App. This way you can use it in all its descendants by passing the state and the mutation function (setActive) as prop:

      App    // Put active state here, pass down active and setActive as prop
       ^
       |
  +----+-----+
  |          |
  +          +
Sidebar     Main  // Pass down active and setActive as prop
             ^
             |
             |
            Menu  // Use setActive to modify state in App

This is explained in React documentation: https://reactjs.org/docs/lifting-state-up.html

With the context api and hooks prop drilling isn’t required anymore. You can simply wrap the parent and child in a context provider and leverage react’s useContext hook for managing state across the 2 components. kent c dodds has a good article with examples here

Related