我仍然对React还是陌生的,最近一直在做一些小项目,以求更好。我目前正在制作一个营养网页,该网页设置卡路里目标并从API中获取食物。该项目由两个组件FoodItem
和Main
组成。
Main
组件计算卡路里并显示来自API的搜索结果。问题就在这里。搜索栏首次收到名称时,不会显示任何内容。但是,它在后退空格(从单词中删除一个字母)后显示预期的搜索结果。在屏幕截图中可以看到。
全字词:
删除一个字母后:
以下是负责显示搜索结果的功能:
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}
  Calories :{this.props.calories}
</div>
);
}
if (!this.state.addDone) {
return (
<div>
{this.props.name}
  Calories :{this.props.calories}
 
<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"));
答案 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
方法所需的内容。