Lit.Elmish compared to useElmish Hook #70
-
So overall I like the general MVU design of Elmish, but i currently have a small JS react codebase I would like to port over to F# (various reasons), and this seemed like it would fit the bill very well. After looking at the Docs, I saw the small example using elmish directly by just using lit for the html, as well as the example for using the useElmish hook to emulate the MVU pattern. Now I am curious, what would other people that have more experience with MVU and Elmish say what the advantages or disadvantages of these 2 approaches would be? Also on a side note, the current code base uses some global state management in some very few places, largely to share state between multiple instances of the same component. What would the preferred approach be here for that? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
They are actually complementary approaches if needed, both work and behave in a similar way. The MVU pattern is a really good one when it comes to make predictable systems, but I feel it is optimized for that, not necessarily for app size. the most difficult for me in pure MVU apps is when apps grow, and you end up with a gigantic update function and several child loops that also have their own big update functions once things go bigger and bigger Some people claim they still had success even for 100k LoC app sizes, but I haven't really seen one of those. Some other people saw this as a potential divergence from pure MVU and more into a hybrid approach: Components + MVU The later leverages the fact that underlying UI frameworks often promote a component model and try to make UI composition that way and that might help scalability once apps grow since each component can and should have its own responsibility and behavior when components become really complex or simply you want to ensure predictability that's where you can fit the MVU pattern with useElmish like hooks In the case of Lit you can actually define the shell of your app as an MVU loop and work as usual, if needed you can extract the functionality of part if your UI into a custom element (the ones that use LitElement attribute) and make it part of your main elmish loop as usual here's a very brief and mostly pseudocode example if we have a counter component here type State = { count: int }
type Msg = Increment | Decrement
let init initial =
{ count = initial }
[<LitElement "my-counter">]
let Counter() =
let _, props =
LitElement.init(fun init ->
// make the component react to external input
init.props <- {| initial = Prop.Of(defaultValue = 0) |}
init.useShadowDom <- false // so you can style it as any other element
)
// initialize the elmish loop with the initial value
let state, dispatch = Hook.useElmish(init props.initial.Value, update)
html
$"""
<article>
<p>{state.count}</p>
<button @click={fun _ -> dispatch Increment}>+</button>
<button @click={fun _ -> dispatch Decrement}>-</button>
</article>
"""
// call this somewhere else in your app to prevent tree-shaking from deleting this file
let register() = () the above component will register itself once the file loads or the register function is called somewhere type Page = Home | About
type State = { page: Page }
type Msg = Visit of Page
let init() =
{ page: Page }, Cmd.none
let update msg model =
match msg with
| Visit page -> { page with page }, Cmd.none
let view state dispatch =
let page =
match state.page with
| Home -> "Home"
| About -> "About"
html
$"""
<h1>{page}</h1>
<my-counter .initial={10}></my-counter>
<button @click={fun _ -> dispatch (Visit Home)}>Visit Home</button>
<button @click={fun _ -> dispatch (Visit About)}>Visit About</button>
"""
open Lit.Elmish
open Lit.Elmish.HMR
MyComponent.register()
Program.mkProgram init update view
|> Program.withLit "app-container"
|> Program.run With the approach above it is fairly simple to keep using both without losing anything at all, you can fall back to custom elements (and hook functions, more info and differences about them here and here) On a technical level one difference would be that pure MVU is just re-rendering HTML on screen on each Elmish (the MVU engine behind) iteration while componments and hook functions do the same but leverage the rendering to the backing component model (LitElement or a Lit directive) but Lit is very performant when it comes to re-rendering on screen so it should not make a notable diference unless the elmish loop degrades its performance due to how it ends up being implemented by the user Sorry if I rambled too much on this but the general tl;dr is: Both work fine and can be combined if necessary the component model is often used to ease scalability concerns but is not necessary both pure MVU and useElmish MVU can be used in the same way since both use the same pattern |
Beta Was this translation helpful? Give feedback.
-
Thanks for your question @JoschuaL and @AngelMunoz for your comments. I subscribe everything that @AngelMunoz says: Elmish vs useElmish is still an ongoing debate in the Fable community (maybe @MangelMaxime wants to chime in). TL;DR; Elmish supporters think it's "more functional", and those who prefer useElmish like that it requires less boilerplate and it's closer to React components (in fact, useElmish is very similar to
In my experience, this are some pros and cons of each approach: ElmishPros
Cons
useElmishPros
Cons
About your comment:
Personally I haven't used global state management tools other than Elmish so not sure how it will work, though my intuition is that it will be complicated to use two tools to do the same thing. |
Beta Was this translation helpful? Give feedback.
They are actually complementary approaches if needed, both work and behave in a similar way.
The MVU pattern is a really good one when it comes to make predictable systems, but I feel it is optimized for that, not necessarily for app size.
the most difficult for me in pure MVU apps is when apps grow, and you end up with a gigantic update function and several child loops that also have their own big update functions once things go bigger and bigger
Some people claim they still had success even for 100k LoC app sizes, but I haven't really seen one of those.
Some other people saw this as a potential divergence from pure MVU and more into a hybrid approach: Components + MVU
The later leverage…