Reputation: 1879
I have an issue trying to update a list of stateful components created with by mapping a list of strings. The issue is showing when i remove one of this components by slicing the array to remove an element by its index.
Every component has his own state, that im fetching from an API. the problems is that when i remove an element of the array, the state of next component overlaps the one that i deleted Component.
My code looks something similar to this:
class MyDashboard extends React.Component {
constructor(props){
super(props);
this.state = {
activeItems: [0,1,2,3],
}
this.removeItem = this.removeItem.bind(this);
}
removeItem(indx){
let tempItems= this.state.activeItems;
tempItems.splice(indx,1);
this.setState({activeItems:tempItems});
}
render(){
let conditionalDash;
let conditionalComponent;
let temporalArray = this.state.activeEntries.map((entry , i) => {
return (<MyDash key={i} index {i}/> removeItem={this.removeItem});
});
render(){
return (
<div id='dashContainer'>
{temporalArray}
</div>
)
}
}
In my MyDashComponent i have a something like this:
class MyDash extends React.Component{
constructor(props){
super(props);
this.state={
fetchedData:null,
}
}
componentDidMount(){
API.fetchData(this.props.index).then(response => {
this.setState({fetchData:response.data})
)
}
render(){
return(
<div> {this.props.index} {this.state.fetchedData}</div>
)
}
}
Is there something that i'm missing?
The behavior that i'm getting is that when the i remove the this.state.activeItems[2] the state of this element is the same as the previous component. I was expecting that the state of the element[2] will be the same state that has the element[3].
Edit: Something that i forget to tell, is that the props of MyDash component are correct, is just the state that doesnt belong to the component, it is from the deleted component.
Thanks for reading and i hope that somebody can help me with this.
Upvotes: 1
Views: 2913
Reputation: 7424
You can also use Array.prototype.filter to remove the item:
removeItem(idx) {
this.setState({
activeItems: this.state.activeItems.filter((_, index) => index !== idx)
});
}
or
removeItem(idx) {
this.setState(prevState => ({
activeItems: prevState.activeItems.filter((_, index) => index !== idx)
}));
}
Upvotes: 0
Reputation: 1879
I found the bug it was that the key of the list that i was using, it was the index of the map method, i read that it has to be a unique key. Luckily this fixed the render action and the state doesnt overlap anymore.
Upvotes: 4
Reputation: 281646
Who have mixed the behaviour or slice
and splice
slice
returns you a new array whereas splice
modifies the existing one
According to MDN docs:
splice:
Thesplice()
method changes the contents of an array by removing existing elements and/or adding new elements.Syntax: array.splice(start, deleteCount)
slice:
Theslice()
method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included). The original array will not be modified.syntax:
arr.slice() arr.slice(begin) arr.slice(begin, end)
You might change your code to
removeItem(indx){
let tempItems= this.state.activeItems;
tempItems.splice(indx,1);
this.setState({ activeItems:tempItems });
}
Also you shouldn't mutate the state directly, you should create a copy of the state array and then update it.
removeItem(indx){
let tempItems= [...this.state.activeItems]; // this is do a shallow copy, you could use something else depending on your usecase
tempItems.splice(indx,1);
this.setState({ activeItems:tempItems });
}
Upvotes: 2