TL'DR: Is there a way to pessimistically operate state changes while using useEffect for API calls?
Lets say you wrote a component that displays a paginated / sorted grid of data and you wrote a useEffect for that component similar to this fake example:
useEffect(() => {
fetch(`https://some-random-api.com/data/page/{paging}/sort/{sorting}`)
.then(response => response.json())
.then(data => setState({
data
}));
}, [paging, sorting]);
So, if I'm not mistaken this will fetch when the paging or sorting states/props (whatev) are updated. This means that it is optimistically rendering the new sorting and paging states before the data is loaded. Basically the app tells the user "I'm on the requested page with the requested sort but I'm still loading it". In other words, part of the app state (the paging and sorting) says "I'm done" the other part of the state (the loading) says "I'm working on it".
By contrast if I were to pessimistically update states I would only set a loading state to true before the fetch and then when a response is received (and only then) set paging, sorting (& data & loading). So the app tells the user "I heard you and I'm now working on it" and then when a successful response is received the app says "here is the requested data and updated context (updated page / sort status)".
The other issue is if the request fails. In the optimisitic/useEffect approach I now need to revert the paging & sorting states that were updated before attempting to load the data for those state changes. That complexity grows with the number of dependencies. Plus, here is the kicker (again, if I'm not mistaken) reverting those states will result in another fetch (which could fail again). In the pessimistic approach you just set loading = false when an error occurs and there's no other state changes to be made because paging & sorting are only updated when the data is successfully received. The data stays synchronized in a pessimistic approach (not optimistic) which is why I think it's ironic when blogs and videos say "think in terms of synchronization" when using useEffect.
One more thing, say an API called from within useEffect (in some other example) was actually changing something on the server-side. In that case when using useEffect and applying it's optimistic approach is just lying to the user. The app is saying "Ok, I updated that". Maybe not. If not (if there was an error) hopefully there's state update to revert the state change that lied to the user and somehow avoids an additional API call when reverting that state. And hopefully the user saw that state change back & hopefully there was a message... Even then, is that a good UX?
I'm not saying optimistic rendering is always bad. I am saying "I like being pessimistic most of the time. How do I do that while using useEffect?" :)
It seems useEffect is being used and promoted for most side effects of apps (A LOT). I'm not finding it useful very often. I'm a pessimist and want to be enabled with an alternative.