I'm working on a project and my team mate and I are discussing which approach is better.
In my opinion Html msg
seems to be more generic, so I think we should use it whenever we can, but I can't give him other reason than that.
Also, I'm coming from React and Redux, and to me looks like components with signature Html Msg
are what we called Smart/Connected Components
and Html msg
are like Dumb Components
, am I right with this supposition?
Could you tell me when I should use each one?
Thank you
Message is a component in the Elm architecture. These components are generated by the View in response to the user's interaction with the application's interface. Messages represent user requests to alter the application's state.
Annotating a view function as returning Html msg
means that you are not tying the view down to a specific Msg
type. It is more flexible because of this but it also limits what you can do.
It is useful to use the lowercase version when writing shared code that does not render any code specific to a particular Msg
. For instance, you could standardize some layout code:
pageTitle : String -> Html msg
pageTitle title =
h1 [ class "page-title" ] [ text title ]
The above code could return Html Msg
but that would limit its ability to share it since you would be tying it to a particular Msg
type.
Now, if you are writing something that has the ability to generate a specific event and you tie it to a Msg
constructor, then you have to return Html Msg
:
type Msg = RollDice | Rolled Int
diceButton : String -> Html Msg
diceButton label =
button [ class "fancy-btn", onClick RollDice ] [ text label ]
The above definition won't compile if you try to return lowercase Html msg
.
If we stopped there, I could see how this might come across as similar to the smart vs. dumb component idea inside React since it seems like the lowercased version can't render Html that would trigger events, but that analogy doesn't really hold. Let's say you wanted to standardize a button system-wide but didn't want to tie it to a particular Msg
. You could make the function more generic by accepting a parameter of the Msg
to be triggered on click.
fancyButton : String -> msg -> Html msg
fancyButton label msg =
button [ class "fancy-btn", onClick msg ] [ text label ]
In general, if you are writing code meant to be shared either internally or as an external package, you will provide more flexibility by using the lowercased version of Html msg
. Doing so, you can still write Html that can trigger events, and like in the fancyButton
example above, it just means you pass a bit of responsibility up to the calling function, which will have to decide what Msg
to pass in.
msg
and Msg
are really fundamentally different kinds of things. The fact that the m
/M
is upper or lower case matters!
type Msg = RollDice | Rolled Int
is defining a new type that's specific to your program. You can call it whatever you want (so long as you start it with a capital letter). In fact, Msg
is really a horrible name here -- what is are these messages about? I don't know!
Instead: type DiceMsg = RollDice | Rolled Int
. Ah -- now I see, this is a type (a message) about dice. Got it! :)
And maybe your program also has:
type Suit = Spades | Hearts | Clubs | Diamonds
type CardMsg = DrawCard | CardDrawn Suit Int
Then you can see what the difference is:
Html DiceMsg
-- this is some html that will produce messages about dice.
Html CardMsg
-- this is some html that will produce messages about cards.
Now let's think about html like h1 [ class "page-title" ] [ text title ]
. What kind of html is that?
You can see that it doesn't produce any messages at all, so it doesn't really make sense to call it Html DiceMsg
or Html CardMsg
. But, it can be composed with any kind of html, right? You could put a title like that above a block of Html DiceMsg
and you get ... a bigger block of Html DiceMsg
.
So this is what Html msg
(lower-case m
) is about: the lower-case msg
means "it can be anything, let the compiler figure it out". The compiler will decide, based on the context you use it in, whether msg
is a placeholder for DiceMsg
or a placeholder for CardMsg
. (In technical parlance, msg
is a type variable.)
msg
For maximum flexibility, you can let the callers of your function control what kind of messages they want your code to produce:
fancyButton : String -> msg -> Html msg
fancyButton label msg =
button [ class "fancy-btn", onClick msg ] [ text label ]
Here, msg
is both an argument type and in the return type. So the compiler can figure out that an invocation like fancyButton "draw a card" DrawCard
will produce Html CardMsg
, while fancyButton "roll the dice" RollDice
will produce Html DiceMsg
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With