[英]How to delete an object from state when it is inside an array of objects
I'm trying to delete an object from an array within an object by the id.我正在尝试通过 id 从对象内的数组中删除一个对象。 I can't figure out how to do this...I've looked at several other posts but I feel like the set up is a little different so I still can't figure it out.我不知道如何做到这一点......我看过其他几篇文章,但我觉得设置有点不同,所以我仍然无法弄清楚。
deleteMeals
doesn't delete the correct object even though I am grabbing the correct meal id.即使我获取了正确的膳食 ID, deleteMeals
也不会删除正确的对象。 The "Monday" is also there as a placeholder / trying to figure things out. “星期一”也作为占位符/试图解决问题。
I had my store
set up differently before, where each meal object had its own day
key, and I was able to delete - except the first object (id: 1) would not delete until it was the last one.我之前的store
设置不同,每个餐点对象都有自己的day
键,并且我能够删除 - 除了第一个对象(id:1)在它是最后一个对象之前不会删除。 I ended up refactoring the store so that each meal object was in an array separated by the actual Day.我最终重构了商店,以便每个膳食对象都在一个由实际 Day 分隔的数组中。
So now I need help with two issues please!所以现在我需要帮助解决两个问题!
const store = {
meals: {
"Monday": [
{
"id": 1,
"recipe_id": 2,
"user_id": 1
},
{
"id": 2,
"recipe_id": 1,
"user_id": 1
},
{
"id": 3,
"recipe_id": 3,
"user_id": 1
}
],
"Tuesday": [
{
"id": 4,
"recipe_id": 4,
"user_id": 1
}
],
"Wednesday": [],
}
}
deleteMeal in App.js App.js 中的 deleteMeal
deleteMeal = (day, mealId) => {
this.setState(prevState => ({
// copy existing state
...prevState,
// update meals key
meals: {
// copy existing meals state
...prevState.meals,
// update day key & filter meals array by id
[day]: prevState.meals[day].filter( ({ id }) => id !== mealId),
}
}));
}
const contextValue = {
recipes: this.state.recipes,
meals: this.state.meals,
addRecipe: this.addRecipe,
deleteRecipe: this.deleteRecipe,
updateRecipe: this.updateRecipe,
addMeal: this.addMeal,
deleteMeal: this.deleteMeal
}
Days Component天数组件
class Days extends React.Component{
render() {
const { day, meals } = this.props
let mealsList;
if (meals[day]) {
mealsList = meals[day]
.map((meal, key) =>
<Meals
key={key}
day={day}
meal={meal}
/>
)
}
return(
<div className="Days">
<h3>{day}</h3>
{meals && meals[day] && mealsList}
</div>
)
}
}
Meals Component膳食成分
class Meals extends React.Component {
static contextType = StashContext;
state = {
recipeTitle: 'No Title',
recipeImageUrl: '',
showModal: false
}
findRecipe = (recipeId, recipes) => {
const recipe = recipes.find( recipe => recipe.id == recipeId)
if (recipe) {
this.setState({
recipeTitle: recipe.title,
recipeImageUrl: recipe.image_url
})
}
}
componentDidMount() {
const { recipes } = this.context
const { meal } = this.props
this.findRecipe(meal.recipe_id, recipes)
}
handleClickDelete = (event) => {
const { day, meal } = this.props
const { id } = meal
event.preventDefault()
this.context.deleteMeal(day, id)
}
toggleModal = () => {
this.setState({
showModal: !this.state.showModal
})
}
render(){
const { recipeTitle, recipeImageUrl, showModal } = this.state;
const { meal } = this.props;
const customStyles = {
overlay: {
background: '#4c645682'
},
content: {
background: 'rgb(240 240 240)'
}
}
const permissions = {
edit: false,
add: false,
delete: false
}
return (
<div className="Meals">
{showModal &&
<DisplayModal
meal={meal}
customStyles={customStyles}
showModal={showModal}
closeModal={this.toggleModal}
label="Meal Modal"
permissions={permissions}
/>
}
<div className="Meals__info">
<div className="info_box left">
<div className="Meals__img">
<img src={recipeImageUrl} alt="Placeholder" />
</div>
</div>
<div className="info_box middle">
<div className="Meals__recipe-title">
{recipeTitle}
</div>
</div>
<div className="info_box right">
<div className="Meals__options">
<FontAwesomeIcon
icon={faEye}
onClick={e => {this.setState({showModal: true})}} />
<FontAwesomeIcon
icon={faBackspace}
onClick={this.handleClickDelete} />
</div>
</div>
</div>
</div>
)
}
}
export default Meals
The recipe id appears to be extraneous, I don't think it is needed, you should be able to delete a meal by day and id.食谱 id 似乎无关紧要,我认为不需要,您应该可以按天和 id 删除一顿饭。
The idea is to shallowly copy the state object at each level you intend to update.这个想法是在您打算更新的每个级别浅复制状态对象。
deleteMeal = (day, mealId) => {
this.setState(prevState => ({
// copy existing state
...prevState,
// update meals key
meals: {
// copy existing meals state
...prevState.meals,
// update day key & filter meals array by id
[day]: prevState.meals[day].filter(({ id }) => id !== mealId),
},
}));
}
You are using the array index as the react key in your Days
component.您正在使用数组索引作为Days
组件中的反应键。
meals[day].map((meal, key) => (
<Meals
key={key} // <-- array index!!
day={day}
meal={meal}
/>
))
If you for example had an array of three meals and you delete the first or second, the react keys would still be index 0 and 1. The length would change and the 3rd meal would no longer be rendered, but because the react key for the first two didn't change react bails on rerendering them.例如,如果您有一个包含三餐的数组并且您删除了第一餐或第二餐,则反应键仍将是索引 0 和 1。长度会改变并且第三餐将不再呈现,但是因为反应键是前两个没有改变重新渲染它们的反应保释金。
We don't recommend using indexes for keys if the order of items may change.如果项目的顺序可能发生变化,我们不建议对键使用索引。 This can negatively impact performance and may cause issues with component state.这会对性能产生负面影响,并可能导致组件状态出现问题。 Check out Robin Pokorny's article for an in-depth explanation on the negative impacts of using an index as a key .查看 Robin Pokorny 的文章, 深入了解使用索引作为键的负面影响。
The important take-away from the linked article is this checklist链接文章的重要内容是此清单
- the list and items are static–they are not computed and do not change;列表和项目是静态的——它们不是计算出来的,也不会改变;
- the items in the list have no ids;列表中的项目没有 ID;
- the list is never reordered or filtered.该列表永远不会重新排序或过滤。
When all of them are met, you may safely use the index as a key .当所有这些都满足时,您可以安全地使用索引作为键。
Array indices are technically acceptable as react keys, so long as you don't mutate the array by inserting or deleting elements from it.数组索引在技术上是可以接受的作为反应键,只要你不通过插入或删除元素来改变数组。 Since your meal
objects have an id
property it should be used for the react key.由于您的meal
对象具有id
属性,因此应将其用于反应键。
meals[day].map(meal => (
<Meals
key={meal.id}
day={day}
meal={meal}
/>
))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.