Реагировать на передачу значения onClick из одного класса в другой

В Tournaments.js у меня есть список имен турниров, каждый из которых имеет уникальный идентификатор, который извлекается из API. Теперь всякий раз, когда я нажимаю на одно из этих названий турниров, я получаю его идентификатор, но мне нужно передать этот идентификатор в Template.js, где я могу получить данные о турнире на основе идентификатора турнира, по которому щелкнули. Я пытаюсь что-то сделать с передачей реквизита от ребенка к родителю, но сейчас я полностью потерян.

Турнир.js:

import React, { Component } from "react";
import Template from './template';

const API = 'http://localhost:8080/api/tournaments';

class Tournaments extends Component {

  constructor() {
    super();
    this.state = {
      data: []
    }
  }

  componentDidMount() {
    fetch(API)
    .then((Response) => Response.json())
    .then((findresponse) => {
      console.log(findresponse)
      this.setState({
        data:findresponse,
      })
    })
  }

  reply_click(event) {
    var targetId = event.target.getAttribute('id');
    console.log(targetId);
  }

  render() {
    return(
      <div class="container">
        <div class="row">
          <div class="col-md-6 col-md-offset-3">
            <div class="jumbotron text-center">
              {
                this.state.data.map((dynamicData, key) =>
                <div>
                  <a href={"/#/template"} id={dynamicData.id} onClick={this.reply_click}>{dynamicData.name}</a>
                  <a href={"/#/addTeams"}><button type="button" class="btn-lisa">Edit</button></a>
                  <Template name={dynamicData.id}></Template>
                </div>
                )
              }
            </div>
          </div>
        </div>
      </div>
    )
  }
}

export default Tournaments;

Шаблон.js:

import React, { Component } from "react";
import Parser from 'html-react-parser';
import Tournaments from "./Tournaments";
import './template.css';
import './index.css';

const tournyAPI = 'http://localhost:8080/api/tournaments';
const teamAPI = 'http://localhost:8080/api/teams'

class template extends Component {

  constructor() {
    super();
    this.state = {
      data: [],
    }
  }

  componentDidMount() {
    fetch(tournyAPI)
    .then((Response) => Response.json())
    .then((findresponse) => {
      this.setState({
        tournydata:findresponse.filter(res => res.id === 18),
      })
    })

Итак, в основном моя цель — использовать targetID из Tournament.js вместо «18» в ComponentDidMount в Template.js.


person Cuzto    schedule 28.04.2018    source источник


Ответы (3)


Вы должны сохранить это значение в родительском компоненте state и передать его в качестве реквизита дочернему компоненту.

Когда ваш onClick уволен, вы должны обновить родителей state, чтобы обновленный props был передан дочернему.

Вот код:

Турнир.js

import React, { Component } from "react";
import Template from './template';

const API = 'http://localhost:8080/api/tournaments';

class Tournaments extends Component {

  constructor() {
    super();
    this.state = {
      data: [],
      targetId: null,
    }
  }

  componentDidMount() {
    fetch(API)
    .then((Response) => Response.json())
    .then((findresponse) => {
      console.log(findresponse)
      this.setState({
        data:findresponse,
      })
    })
  }

  reply_click = id => {
    return () => {
        this.setState({ targetId: id })
    }
  }

  render() {
    return(
      <div class="container">
        <div class="row">
          <div class="col-md-6 col-md-offset-3">
            <div class="jumbotron text-center">
              {
                this.state.data.map((dynamicData, key) =>
                <div>
                  <a href={"/#/template"} onClick={this.reply_click(dynamicData.id)}>{dynamicData.name}</a>
                  <a href={"/#/addTeams"}><button type="button" class="btn-lisa">Edit</button></a>
                  <Template name={dynamicData.id} targetId={this.state.targetId}></Template>
                </div>
                )
              }
            </div>
          </div>
        </div>
      </div>
    )
  }
}

export default Tournaments;

Шаблон.js

import React, { Component } from "react";
import Parser from 'html-react-parser';
import Tournaments from "./Tournaments";
import './template.css';
import './index.css';

const tournyAPI = 'http://localhost:8080/api/tournaments';
const teamAPI = 'http://localhost:8080/api/teams'

class template extends Component {

  constructor() {
    super();
    this.state = {
      data: [],
    }
  }

  componentDidMount() {
    fetch(tournyAPI)
    .then((Response) => Response.json())
    .then((findresponse) => {
      this.setState({
        tournydata: findresponse.filter(res => res.id === this.props.targetId),
      })
    })

Но используйте componentDidUpdate вместо componentDidMount, если хотите обновлять компонент Шаблон после каждого изменения targetId.

Как это:

Шаблон.js

componentDidUpdate(prevProps) {
    if (prevProps.targetId !== this.props.targetId) {
       fetch(tournyAPI)
       .then((Response) => Response.json())
       .then((findresponse) => {
       this.setState({
          tournydata:findresponse.filter(res => res.id === this.props.targetId),
       })
      })
    }
}

Если вам нужно сделать это сразу во время первого рендеринга, просто добавьте проверку, не является ли targetId null в вашем компоненте Tournament.

Что-то вроде этого:

Турнир.js

render() {
    ...
    {this.state.targetId ? <Template name={dynamicData.id} targetId={this.state.targetId}></Template> : null }
    ...
}
person Denys Kotsur    schedule 28.04.2018
comment
Пробовал это, но {this.props.targetId} возвращает undefined в Template.js. Кроме того, должен ли ‹Template targetId={this.state.targetId}›‹/Template› быть внутри рендеринга или он работает и вне рендеринга? - person Cuzto; 28.04.2018
comment
@Ferder Я обновил вашу функцию reply_click в своем ответе. Используйте это так. - person Denys Kotsur; 28.04.2018
comment
@ Фердер, как ты пытался, с каким? componentDidMount или componentDidUpdate? - person Denys Kotsur; 28.04.2018
comment
компонентдидобдате - person Cuzto; 28.04.2018
comment
@Ferder попробуйте использовать его с обновленной функцией reply_click и измените onClick, как это сделал я. - person Denys Kotsur; 28.04.2018

Добавьте targetID в свое родительское состояние и передайте его дочернему:

reply_click(event) {
  var targetId = event.target.getAttribute('id');
  this.setState({ targetID });
}
<Template targetID={this.state.targetID}

В Template вы можете получить к нему доступ с помощью this.props.targetID.

Однако вам нужно использовать componentDidUpdate, см. Дочерний компонент React не обновляется при обновлении состояния родительского компонента

person Roy Wang    schedule 28.04.2018
comment
Этот метод также дает мне Невозможно прочитать свойство setState неопределенного. - person Cuzto; 28.04.2018
comment
Вам нужно связать метод в вашем конструкторе: this.reply_click = this.reply_click.bind(this) или объявить его как reply_click = event => {. - person Roy Wang; 28.04.2018
comment
Спасибо, ошибка устранена, но внутри Template.js {this.props.targetID} по-прежнему возвращает неопределенное значение. - person Cuzto; 28.04.2018
comment
Вы инициализировали состояние с помощью this.state = { targetID: null }? Вам также необходимо изменить componentDidMount на componentDidUpdate; посмотри ссылку которую я дал выше. - person Roy Wang; 28.04.2018

В вашем примере это очень просто, так как вы визуализируете <Template> в цикле, вы можете передать его как параметр

Проблема 1

Цель React не в том, чтобы манипулировать домом подобным образом var targetId = event.target.getAttribute('id') У вас есть этот идентификатор, почему вы получаете его из DOM? Вместо этого примите его как параметр

 <a href={"/#/template"} id={dynamicData.id} onClick={(e) => this.reply_click(e, dynamicData.id)}>{dynamicData.name}</a>

а также

reply_click(event, targetId) {

    console.log(targetId);
  }

Никогда не запрашивайте DOM в React. Вы получите беспорядок и ошибки из-за несмонтированных элементов и т. Д. React использует JSDom (в памяти), а не Real DOM.

Проблема 2

Просто передайте его как параметр

and call setState inside reply_click

reply_click(event, targetId) {

    console.log(targetId);
    this.setState({targetID: targetId})
  }
person Milos Mosovsky    schedule 28.04.2018
comment
Пробовал использовать этот метод, теперь я получаю TypeError: Cannot read property 'setState' of undefined. Я также добавил targetID в часть this.state конструктора. - person Cuzto; 28.04.2018
comment
Вы не изменили ссылку на то, что я отправил ... у нее есть onClick={() =› this.reply_click}, который завершит обратный вызов с этим контекстом - person Milos Mosovsky; 28.04.2018