反应不呈现来自API onChange

时间:2018-07-24 21:37:58

标签: javascript reactjs

我仍然对React还是陌生的,最近一直在做一些小项目,以求更好。我目前正在制作一个营养网页,该网页设置卡路里目标并从API中获取食物。该项目由两个组件FoodItemMain组成。

Main组件计算卡路里并显示来自API的搜索结果。问题就在这里。搜索栏首次收到名称时,不会显示任何内容。但是,它在后退空格(从单词中删除一个字母)后显示预期的搜索结果。在屏幕截图中可以看到。

全字词:

FullWord

删除一个字母后:

After Deleting one letter

以下是负责显示搜索结果的功能:

updateResult(name) {
  console.log(name);
  if (name == "") {
    this.setState({
      foodResult: []
    })
    return;
  }
  let result = [];
  let url = 'https://api.edamam.com/api/food-database/parser?app_id=e056fc58&app_key=key&ingr=' + name;
  fetch(url)
    .then(
      function(response) {
        return response.json();
      }
    ).then(function(jsonData) {
      for (let i = 0; i < jsonData.hints.length; i++) {
        foods.push({
          name: jsonData.hints[i].food.label,
          calories: Math.round(jsonData.hints[i].food.nutrients.ENERC_KCAL)
        })
      }
    })
  console.log(foods);
  foods = removeDuplicates(foods);

  for (let i = 0; i < foods.length; i++) {
    if (foods[i].name.toUpperCase().includes(name.toUpperCase())) {
      result.push(
        <FoodItem name ={foods[i].name} calories ={foods[i].calories} updateFoods = {this.displayEatenFoods} isEaten = {false} checkItem = {this.checkItem}/>)
      }
    }
    console.log(result);
    this.setState({
      foodResult: result
    });
  }

完整代码:

import React from "react";
import ReactDOM from "react-dom";
//////////////////

let foods = [];
function removeDuplicates(arr) {
  var unique = [];
  for (let i = 0; i < arr.length; i++) {
    let current = arr[i].name;
    let add = true;
    for (let i = 0; i < unique.length; i++) {
      if (current == unique[i].name) add = false;
    }
    if (add) unique.push(arr[i]);
  }
  return unique;
}
///////////////////
class FoodItem extends React.Component {
  constructor(props) {
    super(props);
    this.state = { addDone: false, disable: false };
    this.addEaten = this.addEaten.bind(this);
  }

  addEaten() {
    if (this.props.updateFoods(this.props.name))
      this.setState({ addDone: false, disable: true });
    else this.setState({ addDone: true });
  }

  render() {
    if (this.props.isEaten) {
      return (
        <div>
          {this.props.name}
          &ensp; Calories :{this.props.calories}
        </div>
      );
    }
    if (!this.state.addDone) {
      return (
        <div>
          {this.props.name}
          &ensp; Calories :{this.props.calories}
          &ensp;
          <button primary onClick={this.addEaten} disabled={this.state.disable}>
            Eat
          </button>
        </div>
      );
    }
    return null;
  }
}

class Main extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      goal: " ",
      remaining: " ",
      goalEntered: false,
      foodSearch: "",
      foodResult: [],
      EatensFoods: [],
      allowance: " ",
      calories: ""
    };
    this.setGoal = this.setGoal.bind(this);
    this.changeGoal = this.changeGoal.bind(this);
    this.changeFoodSearch = this.changeFoodSearch.bind(this);
    this.displayEatenFoods = this.displayEatenFoods.bind(this);
    this.checkItem = this.checkItem.bind(this);
    this.changeCalorieSearch = this.changeCalorieSearch.bind(this);
  }

  changeGoal(event) {
    this.setState({ goal: event.target.value });
  }

  setGoal(event) {
    this.setState({ goalEntered: true, remaining: this.state.goal });
    event.preventDefault();
  }

  changeFoodSearch(event) {
    this.setState({ foodSearch: event.target.value });
    this.updateResult(event.target.value);
  }

  changeCalorieSearch(event) {
    this.setState({ calories: event.target.value });
  }

  updateResult(name) {
    console.log(name);
    if (name == "") {
      this.setState({ foodResult: [] });
      return;
    }
    let result = [];
    let url =
      "https://api.edamam.com/api/food-database/parser?app_id=e056fc58&app_key=key&ingr=" +
      name;
    fetch(url)
      .then(function(response) {
        return response.json();
      })
      .then(function(jsonData) {
        for (let i = 0; i < jsonData.hints.length; i++) {
          foods.push({
            name: jsonData.hints[i].food.label,
            calories: Math.round(jsonData.hints[i].food.nutrients.ENERC_KCAL)
          });
        }
      });
    console.log(foods);
    foods = removeDuplicates(foods);

    for (let i = 0; i < foods.length; i++) {
      if (foods[i].name.toUpperCase().includes(name.toUpperCase())) {
        result.push(
          <FoodItem
            name={foods[i].name}
            calories={foods[i].calories}
            updateFoods={this.displayEatenFoods}
            isEaten={false}
            checkItem={this.checkItem}
          />
        );
      }
    }
    console.log(result);
    this.setState({ foodResult: result });
  }

  displayEatenFoods(name) {
    let tempEaten = [];
    let disableFlag = false;
    for (let i = 0; i < foods.length; i++) {
      if (foods[i].name.toUpperCase() == name.toUpperCase()) {
        if (this.checkItem(foods[i].calories, foods[i].name)) {
          tempEaten.push(
            <FoodItem
              name={foods[i].name}
              calories={foods[i].calories}
              updateFoods={this.displayEatenFoods}
              isEaten={true}
              checkItem={this.checkItem}
            />
          );
        } else {
          disableFlag = true;
        }
      }
    }
    tempEaten = removeDuplicates(tempEaten);
    tempEaten = this.state.EatensFoods.concat(tempEaten);
    this.setState({ EatensFoods: tempEaten });
    return disableFlag;
  }
  checkItem(cal, name) {
    let newRemainder = this.state.remaining - cal;
    if (newRemainder < 0) {
      this.setState({ allowance: "You can't eat " + name });
      return false;
    }
    this.setState({
      remaining: newRemainder,
      allowance: "You can eat " + name
    });
    return true;
  }

  render() {
    if (!this.state.goalEntered) {
      return (
        <center>
          <form onSubmit={this.setGoal}>
            <label>
              Please Enter your desired calories
              <input
                type="text"
                value={this.state.goal}
                onChange={this.changeGoal}
              />
            </label>
            <input type="submit" value="OK" />
          </form>
        </center>
      );
    }
    return (
      <div>
        <center>
          <h1>Maximum Calories:{this.state.goal}</h1>
          <h2>Remaining Calories:{this.state.remaining}</h2>
          <h3>{this.state.allowance}</h3>
          <form>
            <label>
              Search foods
              <input
                type="text"
                placeholder="Enter Name"
                value={this.state.foodSearch}
                ref={a => {
                  this.searchValue = a;
                }}
                onChange={this.changeFoodSearch}
              />
              <input
                type="text"
                placeholder="Calories,Min+,Max,Min-Max"
                value={this.state.calories}
                onChange={this.changeCalorieSearch}
              />
            </label>
          </form>
          {this.state.foodResult}
          <h2>Eaten Foods:</h2>
          {this.state.EatensFoods}
        </center>
      </div>
    );
  }
}

ReactDOM.render(<Main />, document.getElementById("root"));

1 个答案:

答案 0 :(得分:0)

首先,如果有一些最佳实践而不是逻辑,那么我将无法检查所有代码,但是您的问题是您的updateResult函数正在执行异步工作,但您没有等待它完成。这是您的主要问题。删除一个单词或删除任何内容都不会触发此问题。只需键入“ o”,然后稍等片刻,然后编写任何内容,然后看到同样的问题就会发生。使您的updateResult函数async并在获取之前放置一个await

async updateResult(name) {
    console.log(name);
    if (name == "") {
      this.setState({ foodResult: [] })
      return;
    }
    let result = [];
    let url = 'https://api.edamam.com/api/food-database/parser?app_id=e056fc58&app_key=somekeyhere&ingr=' + name;
    await fetch(url)
      .then(
        function (response) {
          return response.json();
        }
      ).then(function (jsonData) {
        for (let i = 0; i < jsonData.hints.length; i++) {
          foods.push({ name: jsonData.hints[i].food.label, calories: Math.round(jsonData.hints[i].food.nutrients.ENERC_KCAL) })
        }
      })
    console.log(foods);
    foods = removeDuplicates(foods);

    for (let i = 0; i < foods.length; i++) {
      if (foods[i].name.toUpperCase().includes(name.toUpperCase())) {
        result.push(
          <FoodItem name={foods[i].name} calories={foods[i].calories} updateFoods={this.displayEatenFoods} isEaten={false} checkItem={this.checkItem} />)
      }


    }
    console.log(result);
    this.setState({ foodResult: result });
  }

您可以使用其他一个或多个async方法来继续执行代码,而不是使函数成为.then。只是不要忘记返回以前的.then方法所需的内容。