Reputation: 391
I have a Liked method that checks for an existing item in an array, depending on the return value, component Recipe_serving display conditionally. What I notice here is when I add an item into the array (likedList) child component rerender and condition is check, but when I remove item re-render doesn't occur even though setState is used
class App extends Component {
state = {
result:[],
recipe:{},
isActive:"47746",
addToShopping: [],
likedList:[]
}
setActiveId=(id)=>{
this.getRecipe(id)
}
pushToLikeList = () => {
// if id is in likeList then remove
// if id not in likeList then add
if(this.state.likedList.findIndex(el=>el.recipe.recipe_id===this.state.isActive) === -1){
this.setState(prevState => {
return {
likedList: [prevState.recipe, ...prevState.likedList]
}
})
}else{
this.setState(prevState=>{
const index = prevState.likedList.findIndex(el=>el.recipe.recipe_id===prevState.isActive);
prevState.likedList.splice(index,1)
return{
likedList:prevState.likedList
}
})
}
}
Liked=()=>{
return (this.state.likedList.findIndex(el=>el.recipe.recipe_id===this.state.isActive) !== -1)
}
render() {
return (
<div className="App">
<Recipe_serving
isActive={this.state.isActive}
likedList={this.state.likedList}
pushToLikeList={this.pushToLikeList}
Liked={this.Liked}
/>
</div>
);
}
}
const Recipe_serving = (props)=>{
return(
<div>
<button className="recipe__love" onClick={props.pushToLikeList}>
<svg className="header__likes">
<use href={props.Liked?"img/icons.svg#icon-heart":"img/icons.svg#icon-heart-outlined"}></use>
</svg>
</button>
</div>
)
}
Upvotes: 3
Views: 2513
Reputation: 10218
The key is that React checks for the props/state changes only shallowly - any subobjects (and arrays, since they're objects) are checked by reference, not by value.
When you add the item using the spread operator, you're essentially creating a brand new array by cloning the current one, so React notices this and triggers the rerender. When you delete the item, however, it's different, because splice
works in-place, and the reference to array stays the same.
How this could be resolved:
Use slice
to clone the prevState.likedList
before deleting the item with splice
.
Use filter
to create a new array with all existing elements except one.
Use spread operator, as such:
return {
likedList: [...prevState.likedList.slice(0, index), ...prevState.likedList.slice(index + 1)]
}
forceUpdate()
the component after state is set (not recommended, since it breaks the semantics, but possible).Upvotes: 7