Передача данных между компонентами родитель-ребенок

Всем привет. Ситуация следующая. У меня есть два компонента: Header и Searchbox. Searchbox представляет из себя input tupe = "serchbox", в который я ввожу текстовую информацию. Компонент Header является родителем для Searchbox. Т.е. я рендерю searchbox внутри Header. Мне надо, чтобы информация которая была введена в input, который является передавалась в state компонента . Т.е. если более глобально, то есть шапка сайта, в ней input, в котором можно что-то вводить и эти данные должны сохраняться в state родительского компонента . Вот мой код. Компонент Searchbox

import React, { Component } from "react";
import "./style.scss";

class Searchbox extends Component {
  constructor(props) {
    super(props);
    this.state = { name: "", requestResult: null };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    event.preventDefault();
    this.setState({ name: event.target.value });
  }

  handleSubmit(event) {
    event.preventDefault();
    // this.setState({ name: "" });
    console.log(this.state.name);
  }

  render() {
    const { requestResult, name } = this.state;
    return (
      <>
        <form
          id="search_movie"
          className="search-movie"
          onSubmit={this.handleSubmit}
        >
          <input
            type="search"
            value={name}
            onChange={this.handleChange}
            requestvalue={requestResult}
          />
        </form>
        <button
          onClick={name => {
            this.props.getData(name);
          }}
        >
          OK
        </button>
      </>
    );
  }
}
export default Searchbox;

Компонент Header

import React, { Component } from "react";  
import Searchbox from "../Searchbox";
import User from "../User";
import "./style.scss";

class Header extends Component {
  constructor(props) {
    super(props);
    this.state = { name: "" };  
  }

  getData = value => {
    this.setState({ name: value });
    console.log(this.state);
    console.log(value);
  };

  render() {
    return (
      <div className="movie-header">
        <div className="container">
          <div>Movie Catalog</div>
          <Searchbox getData={value => this.getData(value)} />
          <User />
       </div>
      </div>
    );
  }
}

export default Header;

При клике на кнопке "OK" должна срабатывать функция getData(value), которая должна записать значение value в state компонента Header. Почему в моем случае этого не происходит? Вот ссылка на оригинал https://codesandbox.io/s/zealous-villani-u4rsm


Ответы (1 шт):

Автор решения: Denis Bubnov

Проблема кроется в методе обработки клика на кнопку OK вот тут:

onClick={name => {
  this.props.getData(name);
}}

Если вдуматься в смысл, то вы передаете не name вовсе, а event. То есть, нужен обработчик на клик, к примеру такой:

onOkClick = () => {
  const { name } = this.state;
  this.props.getData(name);
};

Тут мы достаем из стейта введенное name и отдаем нашему родителю в метод getData. Этот метод укажем в качестве обработчика для кнопки OK:

<button onClick={this.onOkClick}>OK</button>

Пример кода (на основании вашего) прилагаю тут:

class Searchbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "" };
    
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  
  handleChange(event) {
    event.preventDefault();
    this.setState({ name: event.target.value });
  }
  
  handleSubmit(event) {
    event.preventDefault();
    // this.setState({ name: "" });
    console.log(this.state.name);
  }
  
  onOkClick = () => {
    const { name } = this.state;
    this.props.getData(name);
  };
  
  render() {
    const { requestResult, name } = this.state;
    return (
      <div>
        <form
          id="search_movie"
          className="search-movie"
          onSubmit={this.handleSubmit}
        >
          <input
            type="search"
            value={name}
            onChange={this.handleChange}
            requestvalue={requestResult}
          />
        </form>
        <button
          onClick={this.onOkClick}
        >
          OK
        </button>
      </div>
    );
  }
}

class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "" };  
  }

  getData = value => {
    this.setState({ name: value });
    console.log(this.state);
    console.log(value);
  };

  render() {
    return (
      <div className="movie-header">
        <div className="container">
          <div>Movie Catalog</div>
          <Searchbox getData={value => this.getData(value)} />
       </div>
      </div>
    );
  }
}

ReactDOM.render(
  <Header />, 
  document.getElementById('app')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!-- The content rendered into this tag should match the content below. -->
<div id="app"></div>

В качестве дополнения к ответу, советую обратить внимание на следущий код, написанный вами:

getData = value => {
  this.setState({ name: value }); 
  console.log(this.state);
  console.log(value);
};

Так как метод setState добавляет в очередь изменения в состоянии компонента, то при выводе значения через console.log(this.state); после вызова setState вы не увидите своего значения в полученном результате. Думайте о setState(), как о запросе, а не как о команде немедленного обновления компонента. Можно использовать колбэк вторым параметром в методе setState, чтобы точно получить установленное значение в стейте, например вот так:

getData = value => {
  this.setState({ name: value }, () => { console.log(this.state); }); 
  console.log(value);
};
→ Ссылка