javascript - setState 自动调用 React 中的另一个方法

标签 javascript reactjs

我在我的 React 应用程序中遇到了奇怪的行为。当我向商店添加费用时,会自动调用删除方法 deleteExpense,从而删除我添加的最后一项。如果我从 updateExpense 方法中删除 this.setState ,则不会发生这种情况。无法弄清楚为什么会发生这种情况。这是代码:

App.jsx:

import React from 'react';
import { observer } from 'mobx-react';
import DevTools from 'mobx-react-devtools';

import ExpenseStore from './stores/ExpenseStore';
import AddExpenseView from './components/AddExpenseView';
import CategoryView from './components/CategoryView';

var ExpenseStoreObj = new ExpenseStore();

@observer
export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      allExpenses: ExpenseStoreObj.expenses,
      expenseCategories: ExpenseStoreObj.expenseCategories
    }
    this.updateExpense = this.updateExpense.bind(this);
    this.deleteExpense = this.deleteExpense.bind(this);
    this.categorizeExpenses = this.categorizeExpenses.bind(this);
  }

  updateExpense(newExpense) {
    ExpenseStoreObj.addExpense(newExpense);
    this.setState({
      allExpenses: ExpenseStoreObj.expenses.slice()
    })
  }

  deleteExpense(ExpenseId) {
    ExpenseStoreObj.removeExpense(ExpenseId);
  }

  categorizeExpenses() {
    return ExpenseStoreObj.categorizeExpenses();
  }

  render() {
    return (
      <div className="app-container">
        <div className="col-xs-6 border">
          <AddExpenseView
            allExpenses={this.state.allExpenses}
            expenseCategories={this.state.expenseCategories}
            updateExpense={this.updateExpense}
            deleteExpense={this.deleteExpense}
          />
        </div>
        <div className="col-xs-6 border">
          <CategoryView
            categorizeExpenses={this.categorizeExpenses}
          />
        </div>
      </div>
    );
  }
}

ExpenseStore.js:

import { observable, computed, reaction } from 'mobx';

export default class ExpenseStore {
    constructor(props) {
        this.id = 1;
    }
    expenses = [];
    expenseCategories = ['Food', 'Clothing', 'Transport'];

    handleError(message) {
        alert(message);
    }

    addExpense(newExpense) {
        if (newExpense.expenseName == '') {
            this.handleError('Please enter expense name');
        }
        else if (newExpense.expenseCategory == '') {
            this.handleError('Please select expense categorry');
        }
        else if (newExpense.expensePrice == '') {
            this.handleError('Please enter expense value');
        }
        else {
            newExpense.id = this.id++;
            this.expenses.push(newExpense);
            this.categorizeExpenses();
            console.log('expense store: ', this.expenses);
        }
    }

    removeExpense(expenseId) {
        let expenseIndex = this.expenses.findIndex(x => x.id == expenseId);
        this.expenses.splice(expenseIndex, 1);
        console.log('after deleting expense', this.expenses);
    }

    categorizeExpenses() {
        let groupedResult = this.expenses.reduce(function (hash) {
            return function (r, a) {
                if (!hash[a.expenseCategory]) {
                    hash[a.expenseCategory] = { expenseCategory: a.expenseCategory, expensePrice: 0 };
                    r.push(hash[a.expenseCategory]);
                }
                console.log('hash[a.expenseCategory].expensePrice', hash[a.expenseCategory].expensePrice);
                console.log('a.expensePrice', a.expensePrice);
                hash[a.expenseCategory].expensePrice = parseInt(hash[a.expenseCategory].expensePrice) + parseInt(a.expensePrice);
                return r;
            };
        }(Object.create(null)), []);
        return groupedResult;
    }

}

在检查调用堆栈时,我发现 React 以某种方式调用 ListExpenses.js 中定义的 handleExpenseDelete (它获取 App.jsx 的“removeExpense”函数作为 props。

ListExpenses.js

import React from 'react';
import PropTypes from 'prop-types';
import { observer } from 'mobx-react';

//@observer
export default class ListExpenses extends React.Component {
    constructor(props) {
        super(props);
        this.handleExpenseDelete = this.handleExpenseDelete.bind(this);
    }

    handleExpenseDelete(index) {
        this.props.deleteExpense(index);
    }

    render() {
        var listItems = this.props.allExpenses.map((obj, index) => {
            return (
                <tr key={index}>
                    <td>{obj.expenseName}</td>
                    <td>{obj.expenseCategory}</td>
                    <td>{obj.expensePrice}</td>
                    <td><button onClick={this.handleExpenseDelete(index)}>Delete</button></td>
                </tr>

            )
        });
        return (
            <div>
                <table className="table table-striped table-responsive">
                    <thead>
                        <tr>
                            <th>Item</th>
                            <th>Category</th>
                            <th>Price</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        {
                            listItems
                        }
                    </tbody>
                </table>
            </div>
        );
    }
}

最佳答案

在渲染方法中将 button onClick 更改为如下所示

<td><button onClick={() => this.handleExpenseDelete(index)}>Delete</button></td>

您在渲染时调用该方法。上面的代码只会调用它onClick。

编辑:

当以下代码就位时,方法(handleExpenseDelete)将在渲染期间执行。由于{}大括号表示要执行里面的表达式,所以里面的表达式就是调用函数。

onClick={this.handleExpenseDelete(index)}

当您这样做时,会执行 {} 内的表达式,从而生成一个函数,并且当您单击按钮时会调用该函数。

onClick={() => this.handleExpenseDelete(index)}

关于javascript - setState 自动调用 React 中的另一个方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43465773/

相关文章:

javascript - 在 sails js Node 框架中创建 url

javascript - Reactjs,当可滚动div延伸时如何使滚动保持在当前位置

javascript - 使用 Material UI 和 React.js 创建具有左对齐和右对齐元素的工具栏

javascript - 在 React.js 中推送唯一对象

javascript - 从 dom 中隐藏输入值属性

javascript - 如何创建一个 JavaScript 函数,处理多组输入,并以相同的方式进行数学处理

javascript - element.getText().then(function) 没有被执行

javascript - JQuery单双引号问题

javascript - 更改标志的标签

javascript - 使用 React 和 Redux 在 UI 中处理成功的 REST POST 操作的常见方法是什么