If you're building a tool used in B2B, data curation, or internal tooling uses, I highly recommend creating or finding an interface for confirmation dialogs whose invocation is as simple as `await confirm("...")`. You can even have a hook that lets you memoize and wrap a callback with this, perhaps even making it easy to condition on having unsaved changes. Have it mount in a place that makes sense in your own setup (you can use context, or it can just mount outside your main React mount if you want to cheat), with styling that matches your design system.
You want to make the friction for colleagues to use this as low as possible, so that it will be used by default for dangerous actions, without cluttering your business logic!
(Of course, in implementing such a thing, a state machine is a great choice, and OP's article covers much of the complexity you'll need, though possibly using a library vs. a reducer is overkill!)
I'm using sweetalert2[0] which is good for success error info messages; warning / question confirmation dialogs; and input / select dialogs. Also got a nice optional timer and the animations can be disabled (we do lol)
Self-replying to add that it's important to know when not to use a confirmation dialog (for instance, in a "critical path" of rote data entry), and that your customers may organically show you that things are critical-path that you may not have thought about. In that case, though, having a good abstraction for confirmation dialogs is even more critical, because it's easy to remove (or A/B test) without feeling like you're throwing out significant amounts of effort; it becomes a zero-point story, so to speak. When you're writing less code, there's less code to remove when that becomes necessary, and that's why abstractions are such a big part of our roles!
You want to make the friction for colleagues to use this as low as possible, so that it will be used by default for dangerous actions, without cluttering your business logic!
(Of course, in implementing such a thing, a state machine is a great choice, and OP's article covers much of the complexity you'll need, though possibly using a library vs. a reducer is overkill!)