Межкомпонентная связь React: как передавать данные между компонентами?

218
29 мая 2021, 08:50

Здравствуйте! Вопрос касается связи между компонентами React,а именно: передача данных из одного компонента в другой.

Пусть есть страница <Layout/>, у которой есть массив объектов items. Для каждого элемента items создается компонент <Item />:

Код Layout.jsx:

class Layout extends Component {
  renderItems() {
    var items = [
      {name: 'Ivan', _id: '1'},
      {name: 'Petya', _id: '2'}
    ];
    return items.map( (each) => {
      return (
        <Item each={each} />
      );
    });
  }
  render() {
    return (
      <main> {this.renderItems} <main>
    );
  }
}

Код Item.jsx:

class Item extends Component {
  render() {
    return (
      <div>
        {this.props.each.name}
      </div>
    );
  }
}

Пусть теперь я хочу реализовать по щелчку на каждый <Item />вывод в консоль его _id. Сделать это внутри самого <Item /> не составляет никакого труда:

Новый код Item.jsx:

class Item extends Component {
  printId() {
    console.log(this.props.each._id);
  }
  render() {
    return (
      <div onClick={ this.props.printId.bind(this) }>
        {this.props.each.name}
      </div>
    );
  }
}

Но как быть, если нужно реализовать кнопку "Показать _id" снаружи, то есть в <Layout /> ?

Допустим, внутри каждого <Item/> добавим checkbox. Если этот чекбокс отмечен галочкой как selected, то при нажатии кнопки 'Показать _id' в консоль выводятся _id всех отмеченных Itemов.

Но как передать _id отмеченных Itemов в <Layout /> ?

Заранее благодарен за ответы.

Answer 1

Ответ нашелся сразу в документации, спасибо @AlexeyTen за наводку. Пришлось помучиться, однако решение готов и оно ниже.

При вызове функции из компонента someFunction.bind(this) мы можем передавать любое количество аргументов: someFunction.bind(this, arg1, arg2, ...). В этом и заключается ответ.

Для примера выше: добавим функцию printId в компонент <Layout /> и навесим на компонент <Item /> вызов printId по событию onClick. В качестве аргумента в функцию будем передавать текущий _id элемента. Новый код Layout.jsx:

class Layout extends Component {
  printId(id)
    console.log(id);
  renderItems() {
    var items = [
      {name: 'Ivan', _id: '1'},
      {name: 'Petya', _id: '2'}
    ];
    return items.map( (each) => {
      const eachId = each._id;
      return (
        <Item onClick={this.printId.bind(this, eachId)} each={each} />
      );
    });
  }
  render() {
    return (
      <main> {this.renderItems} <main>
    );
  }
}

Однако, код выше не будет работать. Причина в том, что <Item /> это не настоящий DOM-элемент, соответственно и события OnClick у него быть не может. В строке <Item onClick={this.printId.bind(this, eachId)} /> onCLick является обычным props. Для того, чтобы этот код работал, как ожидается, нужно внутри компонента <Item /> у настоящего DOM-элемента прописать передачу настоящему onClick нашу функцию из props:

class Item extends Component {
  render() {
    return (
      <div onClick={this.props.onClick}>
        {this.props.each.name}
      </div>
    );
  }
}

Теперь все работает как надо.

READ ALSO
TypeError: removeAttr is not a function

TypeError: removeAttr is not a function

Есть обработчик события вставки:

94
jQuery конфликт версий

jQuery конфликт версий

при переносе файлов сайта с одного хостинга на другой, некоторые файлы на сайте не работают корректноВ интернете нашел информацию, касательно...

107
Не работает window.event

Не работает window.event

Опишу ситуацию от начала и до конца, потому что вообще не понимаю происходящее

83