Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elm components and views: When we should use `Html msg` and when `Html Msg`

Tags:

elm

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

like image 639
gabrielperales Avatar asked Sep 04 '17 10:09

gabrielperales


People also ask

What is msg in Elm?

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.


2 Answers

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.

like image 145
Chad Gilbert Avatar answered Jan 02 '23 23:01

Chad Gilbert


msg and Msg are really fundamentally different kinds of things. The fact that the m/M is upper or lower case matters!

User-defined types

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.

Code that works with multiple user-defined types

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.)

Parameterizing with 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.

like image 31
Matt McHenry Avatar answered Jan 03 '23 01:01

Matt McHenry