Kasey Speakman
2017-04-19 23:28:05 UTC
I'm probably slow, but in recent months I've discovered that trying to use
Elm's Model like a database or cache (as I have previously seen suggested)
has turned out to be pretty painful for me. An example database-minded
model where a section could display *either* a list of employees *or* a
list of courses.
type alias Model =
{ employees : List Employee
, courses : List Course
, loadingError : Maybe Http.Error
, route : MyRoute -- employee or course
}
The problem this runs into is having to worry about state management. I
have to remember to "reset" or "turn off" things when they are not active.
As my application grew, I had a lot of problems that boiled down to tedious
state management details. My cached data didn't turn out to be all that
useful because I usually had to reload it anyway, in case something changed.
Instead, I have been moving toward the model only representing the current
state of my UI. The big difference here is the model representing the
current *visual* elements and their data. This leads more to using union
types to represent parts of the UI. When you switch to a different case of
the union type, the data from the previous case is *dropped on the floor*.
This leaves nothing to remember to "reset". RemoteData is a good
micro-example of this. If there was an error fetching the data, when the
user requests the data again, you switch back to Loading, the error message
is dropped on the floor. No forgetting to hide it.
type RemoteData e a
= NotAsked
| Loading
| Failure e
| Success a
If it is really important to cache the data, I prefer to keep that as a
persistence concern, not on Model. It can be part of the process for
retrieving the data to first check my chosen cache before making a request
for fresh data. For instance, first check local storage before making an
HTTP call. (Currently, this scenario is easier with Native modules for lack
of Local Storage API or being able to wait on port subscriptions. But it's
still doable.)
So working towards a Model reflecting the visuals on the page has been an
interesting challenge. I'm not claiming it's easier, but so far I've found
it avoids a class of problems, and has led to some interesting discoveries
in my own apps. One small example: I realized that my LoggedIn and
NotLoggedIn routes should actually be separate "apps". Attempts to model
this in a SPA fashion with the LoggedIn and NotLoggedIn routes as siblings
always came up with the conundrum: how do I make it a compiler error for
the model to be in LoggedIn mode but I receive a NotLoggedIn message, or
vice versa? Even using TEA, I could not avoid this situation. Then I
realized the only way to do that would be as separate apps. And that it was
entirely possible to separate them. My "login page" turned out to be an
entirely self-contained process: the user filling in info, obtaining a
token, and saving it to local storage.
I post this in the slim hope it is helpful to someone.
Elm's Model like a database or cache (as I have previously seen suggested)
has turned out to be pretty painful for me. An example database-minded
model where a section could display *either* a list of employees *or* a
list of courses.
type alias Model =
{ employees : List Employee
, courses : List Course
, loadingError : Maybe Http.Error
, route : MyRoute -- employee or course
}
The problem this runs into is having to worry about state management. I
have to remember to "reset" or "turn off" things when they are not active.
As my application grew, I had a lot of problems that boiled down to tedious
state management details. My cached data didn't turn out to be all that
useful because I usually had to reload it anyway, in case something changed.
Instead, I have been moving toward the model only representing the current
state of my UI. The big difference here is the model representing the
current *visual* elements and their data. This leads more to using union
types to represent parts of the UI. When you switch to a different case of
the union type, the data from the previous case is *dropped on the floor*.
This leaves nothing to remember to "reset". RemoteData is a good
micro-example of this. If there was an error fetching the data, when the
user requests the data again, you switch back to Loading, the error message
is dropped on the floor. No forgetting to hide it.
type RemoteData e a
= NotAsked
| Loading
| Failure e
| Success a
If it is really important to cache the data, I prefer to keep that as a
persistence concern, not on Model. It can be part of the process for
retrieving the data to first check my chosen cache before making a request
for fresh data. For instance, first check local storage before making an
HTTP call. (Currently, this scenario is easier with Native modules for lack
of Local Storage API or being able to wait on port subscriptions. But it's
still doable.)
So working towards a Model reflecting the visuals on the page has been an
interesting challenge. I'm not claiming it's easier, but so far I've found
it avoids a class of problems, and has led to some interesting discoveries
in my own apps. One small example: I realized that my LoggedIn and
NotLoggedIn routes should actually be separate "apps". Attempts to model
this in a SPA fashion with the LoggedIn and NotLoggedIn routes as siblings
always came up with the conundrum: how do I make it a compiler error for
the model to be in LoggedIn mode but I receive a NotLoggedIn message, or
vice versa? Even using TEA, I could not avoid this situation. Then I
realized the only way to do that would be as separate apps. And that it was
entirely possible to separate them. My "login page" turned out to be an
entirely self-contained process: the user filling in info, obtaining a
token, and saving it to local storage.
I post this in the slim hope it is helpful to someone.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.