The stack we are using at work is React + Redux + redux-loop + TypeScript + fp-ts ecosystem.
Redux is a given, since it’s quite popular in the React community and it follows the Elm archicture.
Redux-loop is a port of Elm’s effect system and a solution for Redux’s async flow problem that is usually solved by redux-saga.
TypeScript is self-explanatory, but don’t expect it to be able to pick up types as consistently as Elm, you’ll need to help it with type arguments/annotations quite often, depending on how much use you advanced type techniques.
fp-ts is an ecosystem of libraries for functional programming in TypeScript, the main library exposes useful structures like Option and Either (Maybe and Result in Elm) and also things that you might like but are not possible in Elm - higher-kinded types and monad transformers. There are also other fp-ts libraries like io-ts (JSON decoders), remote-data-ts (RemoteData in Elm), monocle-ts (Lens), parser-ts (Parser combinators) and other.
Thanks for the reply. I will have a look at the libs (ts-*) that you refer to.
For Redux, I must admit I don’t understand the need for a “library” for managing the Model. I mean, in Elm, it’s only about invoking update, right ? What are the benefits of Redux compared to a simple update function (and some Html/Cmd/.map equivalent) ?
I’ve tried to poke around this idea. Couldn’t it simply look like this:
Also, there’s one big difference as far as I understood. Redux users don’t seem to use the container for everything in their Model : they seem to use stateful components because “it’s cumbersome to manage everything in Redux”… Do you second that ? Do you need to choose between TEA and stateful for every component you include in the app ? How do they “mix and match” ?
The code you shared would probably work, but you basically reimplemented redux minus all of the performance optimizations (also your implementation is not that simple, it’s probably the same size in terms of LoC as redux’s source code). Also getting the state at the root and passing it all the way down may work in Elm, but in React it will absolutely destroy the performance of the app, from personal experience with such an architecture you should expect ~300ms+ to update an input value, and that’s on a simple form.
You shouldn’t have any issues storing everything in the store, most people advocating for writing mostly stateful components are either lazy or they have been burned by the performance issues I mentioned above. The best way to mix and match, in my opinion, is to store everything in the store but to use the connect function from react-redux in lower levels in the component hierarchy, not just at the root. That way you still have a single source of truth, but you also skip all of the boilerplate/performance penalties of “drilling down props” as its called in the React community.
Thanks again for your comments, and taking time to look at the sample.
I wrote this in a few hours just to help me structure my thoughts. It is clearly not production code. I was assuming Redux would be a bit more complex than stuff hacked so quick (and dirty), especially with this “middleware” thing and not supporting async by default, and all the noise there is around it
The heart of my code is basically the view/dispatch/update loop and it is 10 or 20 LOC :
I’m interested in what kind of optimization you refer to concerning the store ? How can it behave better than “native” Object spread calls ?
You seem to be confirming what I though about going up to the root and down again at every update. I guess “stateful” React only updates sub-trees, not the whole thing. I guessed performance would be bad with my approach of rendering everything at every single update… Not maybe as bad as what you describe, though. Scary stuff.
But how can this work assuming that you have everything in the store, and it is immutable ? You also need to copy everything on the path from what you have updated, up until the root of the store, don’t you ? So React needs to render everything again (ie do the full diff from root), doesn’t it ?
I’m sorry about the way I’ve formulated my comments, when I’ve referenced redux I was mostly talking about the react-redux library, which binds the redux store to react components.
The way react-redux works is you connect components to the store by giving it a mapStateToProps function that will map the whole app state to whatever parts of the state your component needs. The connect function also does shallow comparison of the props so that no wasteful rerenders happen. To go back to my point from my previous comment, I advise just getting whatever value you need from the store directly in the component with connect (you can also look at reselect, a library for optimizing this process).
There are two possible extremes you want to avoid - connecting to the store at the root and passing everything down vs not passing anything, connecting to the store every time you need some state. It’s hard to find a balance and it depends on the application and other factors.
Understood, thanks for the explanation, much appreciated.
This is exactly what I was afraid of, this kind of “balance” that one needs to find depending on the situation. This is probably why I think Elm is so good.
I’ll probably change my mind a few times again, I’m in early inception stage, but I feel like using “good old” stateful components might just be easier. I know the problems with distributed state etc, but I’ve lived with this for many years and I know how this works.
Sad to say, but it feels like TEA with React (ie Redux, connect and all that jazz) is a bit too much overhead for the benefits (not enforced, left as a design choice, and not coming with Elm’s guarantees)