Реакт запускает функцию несколько раз, но я не назвал ее - PullRequest
0 голосов
/ 11 января 2019

Я использую таблицу реагирования (https://github.com/react-tools/react-table) для отображения таблицы расходов. В одном столбце должна быть кнопка для «утверждения» расходов. Это обрабатывается так:

const columns = [
  {
    Header: "Description",
    accessor: "description"
  },
  {
    Header: "Approve",
    accessor: d => {
      return <button onClick={this.approveExpense(d.id)}>Approve</button>;
    },
    id: "approved"
  }
];

Где функция ApproveExpense определяется как:

  approveExpense = id => {
    fetch(`${apiRoot}expenses_pending/`, {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        Authorization: `Token ${this.props.auth.token}`
      },
      body: JSON.stringify({
        id: id
      })
    }).then(res => {
      if (res.status === 200) {
        this.setState({
          issues: this.state.expenses.filter(expense => expense.id != id)
        });
      } else {
        console.log("Error");
      }
    });
  };

Как ни странно, когда страница загружается, она ведет себя так, как будто все эти кнопки нажимаются многократно, много раз в секунду (пока фанаты не начнут сходить с ума, и я не остановлю сервер реакции).

Я что-то делаю глупо?

Полный класс:

class ExpensePendingAdmin extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    fetch(`${apiRoot}expenses_pending`, {
      method: "GET",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        Authorization: `Token ${this.props.auth.token}`
      }
    })
      .then(response => response.json())
      .then(data => {
        console.log(data);
        this.setState({
          expenses: data
        });
      });
  }

  approveExpense = id => {
    fetch(`${apiRoot}expenses_pending/`, {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        Authorization: `Token ${this.props.auth.token}`
      },
      body: JSON.stringify({
        id: id
      })
    }).then(res => {
      if (res.status === 200) {
        this.setState({
          issues: this.state.expenses.filter(expense => expense.id != id)
        });
      } else {
        console.log("Error");
      }
    });
  };

  render() {
    const columns = [
      {
        Header: "Description",
        accessor: "description"
      },
      {
        Header: "Logged At",
        id: "loggedAt",
        accessor: d =>
          moment(d.expense_incur_datetime).format("HH:mm - ddd d/M/YYYY")
      },
      {
        Header: "Amount",
        accessor: d => `£${d.amount}`,
        id: "amount"
      },
      {
        Header: "Approve",
        accessor: d => {
          return <button onClick={this.approveExpense(d.id)}>Approve</button>;
        },
        id: "approved"
      },
      {
        Header: "Paid",
        accessor: d => {
          console.log(d);
          return d.is_unpaid ? "No" : "Yes";
        },
        id: "paid"
      }
    ];

    return (
      <div className="container-fluid">
        {this.state.expenses ? (
          <>
            <div className="row">
              <div className="col text-center">
                <h2>Pending Expenses</h2>
              </div>
            </div>
            <div className="row">
              <div className="col">
                <ReactTable
                  data={this.state.expenses}
                  columns={columns}
                  minRows="0"
                  minWidth="50"
                  showPagination={false}
                />
              </div>
            </div>
          </>
        ) : (
          "LOADING"
        )}
      </div>
    );
  }
}

Ответы [ 4 ]

0 голосов
/ 11 января 2019

Вам необходимо передать функцию ApproveExpense () как функцию обратного вызова, поэтому она будет срабатывать только при нажатии.

<button onClick={(d) => this.approveExpense(d.id)}>Approve</button>
0 голосов
/ 11 января 2019

Проблема с вашим кодом в том, что вы неправильно передаете обработчик событий:

  return <button onClick={this.approveExpense(d.id)}>Approve</button>;

, используя непосредственно this.approveExpense (d.id) внутри вашего JSX-кода, вы сообщаете javascript выполнить эту функцию, как только интерпретатор ее прочитает. Вместо этого вы должны прокси-функцию выполнения функции по щелчку, как это:

  return <button onClick={(e) => {this.approveExpense(d.id)}}>Approve</button>;

Более подробное объяснение того, как передавать функции компонентам в React, вы можете проверить https://reactjs.org/docs/faq-functions.html

0 голосов
/ 11 января 2019

Все остальные ответы верны, однако вы также можете улучшить синтаксис вызова вашей функции, сделав так, чтобы ваша функция имела несколько наборов параметров:

approveExpense = id => ev => {

А затем настройте визуализацию вашего аксессора следующим образом:

accessor: d => <button onClick={this.approveExpense(d.id)}>Approve</button>;

Функция: this.approveExpense(d.id) вернет другую функцию, способную получить другой параметр (здесь имена событий щелчка ev) и будет работать как талисман

0 голосов
/ 11 января 2019

Методы в обработчиках событий в JSX не требуют скобок, если вы хотите передать параметр, просто заключите его в функцию:

onClick={() => this.approveExpense(d.id)}
...