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 是完全正确的:您似乎在父组件和子组件中拥有相同的数据。只需将其保存在父组件中,然后将数据和更新函数传递给子组件即可。
我想做的是通过添加用户按下的按钮名称的字符串来更新状态数组。用户有几个按钮,所以在按下所有按钮后,我应该留下一个与用户按钮按下相关的字符串数组。
首先,我向用户发出警报,告诉他们添加了哪些食物,然后我只是尝试将该食物的名称附加到 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 是完全正确的:您似乎在父组件和子组件中拥有相同的数据。只需将其保存在父组件中,然后将数据和更新函数传递给子组件即可。