Как отправить состояние из дочернего компонента в другой компонент в React

#javascript #reactjs

#javascript #reactjs

Вопрос:

У меня проблема с отправкой состояния от дочернего элемента к родительскому. После нажатия на меню в главном компоненте я хочу изменить состояние active и отправить это active в компонент боковой панели, потому что я хочу скрыть / показать боковую панель, зависящую от активного класса из css. В Vanilla JS это просто, но в React я немного запутался.

Главная:

 import Menu from "./Menu";

import "./Styles.css";

import teamsdb from "./teamsdb";

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

Меню:

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

export default Menu;
  

Боковая панель:

 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>
      );
    }
  

Комментарии:

1. Где вы используете <Sidebar /> компонент?

2. В основном файле App.js .

3. Не могли бы вы также поделиться этим файлом? Спасибо!

4. Хорошо, я добавляю App.js на вопрос

5. Всякий раз, когда вы хотите передать состояние из дочернего компонента в родительский компонент, вы должны поднять состояние до родительского компонента. Вам нужно будет поддерживать состояние в самом родительском компоненте, а также добавлять обработчики событий для изменения состояния прямо в родительском компоненте. И затем вы можете передать это состояние в качестве реквизита дочернему компоненту. Таким образом, он сохраняет состояние, и ваш родительский компонент также имеет доступ к состоянию.

Ответ №1:

Вы должны поднять свое состояние до первого общего компонента-предка, в вашем случае: App. Таким образом, вы можете использовать его во всех его потомках, передав состояние и функцию мутации (SetActive) в качестве 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

  

Это объясняется в документации React:https://reactjs.org/docs/lifting-state-up.html

Комментарии:

1. Спасибо, чувак, я не знал, что я могу установить setActivate в качестве prop 🙂 Но сейчас работает очень хорошо 🙂

Ответ №2:

С контекстным api и хуками больше не требуется сверление реквизитов. Вы можете просто обернуть родительский и дочерний компоненты в поставщике контекста и использовать перехватчик useContext от react для управления состоянием между 2 компонентами. у Кента си Доддса есть хорошая статья с примерами здесь

Комментарии:

1. Интересно почитать, Context API действительно предлагает альтернативу prop drilling, однако для этого требуется больше шаблонов. Итак, как вы выбираете между детализацией реквизита и контекстом на практике? Используете ли вы жесткие правила, такие как: не сверлить более чем на 2 уровнях или более чем на 3 компонентах?

2. на самом деле это просто зависит от сложности состояния приложения. в более крупных проектах я считаю предпочтительным использовать несколько контекстов для группировки компонентов, которые зависят от состояния, которое содержит каждый контекст (почти как ограниченный контекст в domain driven design). Что касается жестких правил, то это действительно зависит от инженера, который работает над проектом, я обычно придерживаюсь чего-либо на 3 уровня ниже или состояния, которое используется более чем 3 компонентами, я склонен использовать контекст.

3. Спасибо, полезно получить такую практическую информацию о дизайне React! У вас был бы хороший материал по дизайну, управляемому доменом, с React?

4. На самом деле это не относится к React, но я настоятельно рекомендую книгу Вона Вернона Domain Driven Design Distilled, если вы заинтересованы в DDD.