Which design decisions are you thinking of?
Mostly that updates can only happen on explicit changes to the state. Also a React application doesn't acknowledge the possibility of a component existing which is not a React component. I most recently ran into this issue when trying to add an OpenLayer map to an application. In a vanilla JS application it's trivial, but React was difficult to coerce into breaking it's own rules to accommodate it.Elm solves this particular issue well with Ports [1]. It respects the possibility that there may be things going on that haven't been explicitly planned for.
actions are insanely laborious to construct
On a second read through, this is edging on hyperbole. Maybe a more honest presentation of the facts is that Redux actions grow tedious to write. You start with an action type declaration: export const SOME_ACTION = "SOME_ACTION";
Then you create an action creator: export function performSomeAction(data) {
return {
type: SOME_ACTION,
data
}
}
And then of course you need to write a case statement in a reducer to deal with the data and somehow effect the state.It's tedious because it's trying to recreate the pattern matching functionality of passing union types around in functional languages. In SML, Haskell, Elm etc. you can elegantly decompose and consume types with case statements and pattern matching, which are built into the languages [2, 3].
[1] https://guide.elm-lang.org/interop/javascript.html [2] https://stackoverflow.com/a/14604042 [3] http://www.cs.cornell.edu/courses/cs312/2004fa/lectures/lect...
Per the "non-React components" aspect: wrapping up non-React code into components is actually something React is pretty good at. The typical implementation of a maps lib wrapper component would have React render a single div with a ref, then use `componentDidMount` to initialize the plain JS lib and hand it the div. From there, the lib can attach any extra elements it wants, and React won't care. React's lifecycle methods like `componentWillReceiveProps` and `componentDidUpdate` are used to call the imperative lib APIs, and the lib would be cleaned up in `componentWillUnmount`. I wrote a blog post that demonstrates using React components to wrap up the Cesium 3D globe library [0], there was a great talk at ReactBoston that shows doing the same for Mapbox [1], and I have links to other similar articles about interacting with non-React code [2].
Per my other comments elsewhere in the thread, it's up to you how much abstraction you want to use for actions and reducers. A common suggestion is the Redux-Actions lib, which provides utilities for defining action creators and reducers. You can even use the action creators themselves as the "constants" for the reducer cases, since they have custom `toString()` methods.
Also, switch statements aren't a requirement either - they're just the most obvious way of handling multiple values in a single `action.type` field. You can write whatever conditional logic you want in a reducer.
All that said, I do agree that the JS language as a whole does not have the built-in pattern matching capabilities that other languages have.
[0] http://blog.isquaredsoftware.com/2017/03/declarative-earth-p...
[1] https://speakerdeck.com/shortdiv/supercharge-your-maps
[2] https://github.com/markerikson/react-redux-links/blob/master...