The solution in each of these cases is the same, though. To simplify the state.
In general, I think a lot of the pain in web development comes from attempting to have shared mutable state between backend and frontend. Shared mutable states are almost always messy. You can get around that by pushing it all to the frontend, or pushing it all to the backend. It's when it's straddling both you're in for a headache.
The issue I have is we had a great idea to refresh parts of a page with AJAX and then we went overboard and tried to move the entire application to complex frameworks which add more problems then they solve. We became so scared of screen rendering we avoided at all costs. This is bad UX as users actually get good confirmation that something has happened when there is a screen refresh.