Reputation: 2259
I have a list of elements, each of them I can delete by clicking on them (click fires the call to the server, which sends back new list, without the deleted item).
But I need to visually delete them from the view before the response from the server arrives.
I do it like this
state = {
items: this.props.items,
deletedItem: null
};
onClickDelete = (item) => {
const {items} = this.state;
const itemsCopy = {...items};
for (const [key, value] of Object.entries(itemsCopy)) {
if (value.id === tag.id) {
delete itemsCopy[key];
this.setState({
items: itemsCopy,
deletedItem: value
});
}
}
reduxActions(item)
};
So that is happening:
My initial items are from props. When I click on the item I filter it out of state ( this way the item disappears from the view right away). Then I send action which performs a request to the server.
But is that the request to the server can return with an error. In that case, I want to return the deleted item to the state, so it will appear again.
Initially, I thought to create a flag in my Redux state, like itemDeleted: true
. In case of successful request it stays true
, in case of an error - it becomes false
.
The problem as follows:
To react and redraw the component, adding an item, I'm doing something like this in my render method
if (!itemDeleted && !!deletedItem) { this.returnOnError(); }
And the function is
returnOnError= (): void => {
const { deletedItem } = this.state;
this.setState(prevState => ({
items: {
...prevState.items,
[deletedItem.id]: deletedItem
}
}));
};
This causes two issues - one is that I'm calling setState
in the render. Another is that when I click an item with error - the property itemDeleted
becomes false and if I click again and get error again, the itemDeleted
is already false so returnOnError
fires anyway, without waiting for the result from the server.
I kind of lost there, all the help will be appreciated. The only restriction is that I need to delete the item before getting a response from the server.
Upvotes: 0
Views: 273
Reputation: 17858
What you are trying to do is called "optimistic UI updates".
1-) Before deleting an item, save the original items.
2-) Update the UI immediately without waiting api call.
3-) In case of api error, recover the original items back.
You can try something like this:
handleDelete = async item => {
/* store the current state in previousItems, just in case of server side fail */
const previousItems = this.state.items;
/* optimistically update on react side */
const items = this.state.items.filter(p => p.id !== item.id);
this.setState({ items });
/* If server side fail, rollback the state */
try {
await axios.delete(apiEndpoint + "/" + item.id);
} catch (e) {
this.setState({ items: previousItems });
}
};
Here is a sample working codesandbox using react-redux to illustrate this.
Upvotes: 1