elm

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


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


Solution

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