Some conveniences for implementing the update function with fetch.
Using the various functions in ccapndave/elm-update-extra is also highly recommended.
Like Update.Extra.sequence, but for update signatures that also
return a list of extra messages for the caller to handle.
Essentially, this allows you to recursively apply a whole sequence of messages,
collecting their results. So, with Update.Extra.sequence you can do something
like this:
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
SomeMsg ->
sequence update
[ AnotherMsg, YetAnotherMsg, AThirdMsg ]
( model, Cmd.none )Isn't that nice? Essentially, you get a really expressive way of constructing
a "composite" message. Plus, you can do something first ... that is, you could
modify the model, and have your own Cmd, and then feed that into the sequence
for further processing.
So, what is sequenceExtra? It deals with an alternative update signature,
in which we're returning a third element to our tuple, with extra messages that
the caller is expected to handle. So, you can follow the same idiom as shown above.
update : Msg -> Model -> ( Model, Cmd Msg, List extraMsg )
update msg model =
case msg of
SomeMsg ->
sequenceExtra update
[ AnotherMsg, YetAnotherMsg, AThirdMsg ]
( model, Cmd.none, [] )
The primary purpose of the
updatefunction is to take amsgand return an updatedmodel(and possibly aCmd). So, what one ordinarily does in anupdatefunction is run acasestatement on themsg, doing whatever is appropriate for the providedmsg.However, there are times when we want to take certain actions based not on the
msgwe just received, but instead on the state of ourmodelgenerally ... particularly the state of whatever is controlling ourview. For instance, we may need to load some data from the backend in order to support the current view. That will require aCmd, but it is logically independent of the currentmsg. Well, I suppose you could try to "catch" every message that creates a requirement to fetch some data, but that is error prone -- it would be nicer to just compute what messages are necessary, given the state of the model.So, imagine that you have a function like this:
Its job is to look at the model and decide whether there are any messages that ought to be processed (e.g. to fetch some needed data, but it isn't really limited to that). It's convenient for this to be a separate function (that is, separate from
update), because it doesn't depend on themsg... it will be a function of something in the model which indicates what theviewneeds.However, we also need to apply this
fetchfunction. That is whereandThenFetchcomes in. You provide:fetchfunctionupdatefunctionWhat you get back is a function that has the same signature as your
updatefunction ... that is, it is also in the formMsg -> Model -> (Model, Cmd Msg). However, after it calls your ownupdatefunction, it calls yourfetchfunction with the resultingModel, and then feeds those results back into yourupdatefunction. So, whatever messages yourfetchfunction returns will be processed.Note that this will run recursively ... that is, when your
fetchfunction returns some messages to process, it will be called again with the results of processing those messages. So, you will need something in your model to keep track of actions in progress (e.g.RemoteData) so that you don't repeatedly kick off the same action in an infinite loop.To use this function, you would normally just supply the first two parameters ... that is, your
fetchfunction and your normalupdatefunction. What you will then get back is a function of the formmsg -> model -> ( model, Cmd msg)... that is, anupdatefunction that you can then pass toprogramWithFlags(or use in another way).Your
mainfunction would look something like:App.Update.updateis your normal update function.App.Fetch.fetchwill likely look something like this, assuming you have a Page calledItems: