Toggling Favorite, a like, a checkbox should feel instant. Waiting for the server is slow. We apply the change to the UI right away (optimistic) and send it to the server in parallel. If the server rejects it — we roll back.
The problem it solves
Between the optimistic apply and the server response, half a second can pass, and the user can toggle several more. Just storing the "previous state" in a variable — competing toggles break the rollback logic.
Operators and why they matter
Subject — receives UI commands (toggle a, toggle b).
mergeMap — independent mutations of different entities run in parallel. Toggle a doesn't block toggle b.
catchError — a server error becomes a rollback event instead of a failure of the whole stream.
scan — a reducer applies the sequence of optimistic/confirm/rollback events to the state.
Gotchas
switchMap — toggle b cancels the already-in-flight save for toggle a. Half the changes are lost.
concatMap — every toggle waits for the previous one to finish. The optimistic feedback is no longer "instant".
The rollback must know the INVERSE value (or the previous one). Otherwise, with two toggles of the same entity in a row, the rollback restores the wrong thing.
What you get
The UI feels instant, but on a server rejection the state rolls back correctly. The user sees the truth.