I swerved out of the way of the Flux architecture that took over the mainstream and kept using “uncontrolled” forms and a much simpler and more sane approach to state management. You know, treating a view as a view.
My current approach is using F# and Fable to compile to a React app that uses parallel client/server express middleware to support the same code handling a client without JS enabled as the SPA that handles when the client does have JS.