Sorry this answer doesn’t really address your question, just adds an observation.
I don’t have a good handle on how exactly Html.lazy
works, but I think it doesn’t integrate quite so well with the use of extensible records to restrict argument types.
As I understand it, the idea is to not use nested records, but instead have a flatter Model
and use extensible record types to constrain the types of functions. The example Richard Feldman gives in his ‘Scaling Elm Apps’ talk (https://www.youtube.com/watch?v=DoA4Txr4GUs) is an Address
type. Which you might write something like:
type alias Address = { street : String, city : String, country : String }
alterAddress : String -> Address -> Address
and then have that on your Model
type as
type alias Model = { address : Address, ... other fields }
But you then have to do nested record update in your update
function, and his point is that you can get the same effect if you do:
type alias Address r = { r | street : String, city : String, country : String }
alterAddress : String -> Address r -> Address r
and then have that on your Model
type as
type alias Model = { street : String, city : String, country : String , ... other fields }
Then you do not need to do nested record update since you can just pass the model into alterAddress
and the types work out and the function is just as restricted as before, profit.
One great thing about this approach, is that if you find a viewBlah
function, needs something more from the model, you can just add it to the extensible record type, and you do not need to change anything else in your code, you don’t need to change any call sites (assuming they are passing the larger record), and you don’t even need to update the parameters line of the function definition (just the type).
If I understand Html.lazy
correctly though, this would kind of break something like:
viewAddress : Address -> Html Msg
...
view : Model -> Html Msg
view model =
div []
[ ....
, Html.lazy viewAddress model.address
, ...
]
Which would work in the original fashion, in that the function viewAddress
would only be re-invoked if the actual address
field of the model has changed. But if you use the above extensible record version then you do:
viewAddress : Address r -> Html Msg
...
view : Model -> Html Msg
view model =
div []
[ ....
, Html.lazy viewAddress model
, ...
]
Now viewAddress
is invoked whenever anything in the model is changed, which is presumably in response to most messages.
A similar question would be when you update the model with the same field. Sometimes you might do something like the following in your update
function:
SelectAddress addressId ->
let
newAddress =
Dict.get addressId model.allAddresses
|> Maybe.withDefault model.selectedAddress
in
( { model | selectedAddress = newAddress }, Cmd.none )
So in the case that the address is not found the model is actually left unchanged, but I believe that it will fool Html.lazy
because you will actually create a new Model
record which just happens to have the same fields as before. I doubt this is a bit issue.