React Array in State 更新晚

React Array in State updating late

我想做的是通过添加用户按下的按钮名称的字符串来更新状态数组。用户有几个按钮,所以在按下所有按钮后,我应该留下一个与用户按钮按下相关的字符串数组。

首先,我向用户发出警报,告诉他们添加了哪些食物,然后我只是尝试将该食物的名称附加到 state 数组中。之后我将该数组传递回父组件以在那里更新类似的数组。

我遇到的问题是,当我按下其中一个食物选项时,状态数组不会更新,但我确实收到了正确的警报。当我尝试添加第二个食物时,数组状态更新为我选择的第一个选项。从那时起,每次我尝试添加一个食物项目时,状态数组都会更新我之前选择的食物。

我认为问题在于我正在以 React 不会立即执行的方式更新状态。我知道在 React 中不能保证状态更新。

抱歉久了post,感谢您的宝贵时间。

import React from "react";
import "./style.scss";
import FoodData from "./foodData.json";

class Food extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      foodData: [],
      addedFoods: []
    };
    this.handleClick = this.handleClick.bind(this);
  }

  componentDidMount() {
    // Build a new array of objects from FoodData
    const newFoodData = FoodData.map(
      ({ name, pic, serving, calories, sugar, protien }, index) => ({
        id: index,
        name,
        pic,
        serving,
        calories,
        sugar,
        protien
      })
    );
    // Assign the new object to state
    this.setState({ foodData: newFoodData });
  }

  handleClick(e) {
    alert("Added " + e.target.name);
    this.setState(
      {
        addedFoods: [...this.state.addedFoods, e.target.name]
      },
      this.props.updateAddedFoods(this.state.addedFoods)
    );
  }

  render() {
    const displayFood = () => {
      let foodItems = []; // Crate an array
      for (let i = 0; i < this.state.foodData.length; i++) {
        foodItems.push(
          // push item to array through the loop
          <div className="food-card" key={i}>
            <img src={require(`${this.state.foodData[i].pic}`)} />
            <ul>
              <li>{this.state.foodData[i].name}</li>
              <li>Serving: {this.state.foodData[i].serving}</li>
              <li>Calories: {this.state.foodData[i].calories}</li>
              <li>Sugar: {this.state.foodData[i].sugar}</li>
              <li>Protien: {this.state.foodData[i].protien}</li>
            </ul>
            <button
              onClick={this.handleClick}
              name={this.state.foodData[i].name}
            >
              Add
            </button>
          </div>
        );
      }
      return foodItems;
    };

    return (
      <div>
        <div className="food-container">
          {!this.state.foodData.length ? <h1>Loading ...</h1> : displayFood()}
        </div>
      </div>
    );
  }
}

export default Food;

setState 的第二个参数应该是函数而不是函数调用。当新状态基于旧状态时,最好使用 setState(oldState => newState)

  handleClick(e) {
    const name = e.target.name;
    alert("Added " + name);
    this.setState(oldState => ({
        addedFoods: [...oldState.addedFoods, name]
      }),
      () => this.props.updateAddedFoods(this.state.addedFoods)
    );
  }

setState 是异步的,因此当您将 this.state.addedFoods 作为参数传递给 this.props.updatedAddedFoods 时,您传递的是更改前的状态。由于您似乎在复制数据,我是否建议仅 parent 具有食物数组并将其作为道具传递给 child?

因此,正如我在评论中所说,我认为 handleClick() 是问题所在,更确切地说是您如何更新状态。
您能否尝试按如下方式编写该函数:

handleClick(e) {
    const newAddedFoods = Object.assign([], this.state.addedFoods);
    newAddedFoods.push(e.target.name);

    this.setState({addedFoods: newAddedFoods }, () => this.props.updateAddedFoods(newAddedFoods));
}

尽管如此,@Iarz 是完全正确的:您似乎在父组件和子组件中拥有相同的数据。只需将其保存在父组件中,然后将数据和更新函数传递给子组件即可。