| The absolute most important thing to understand about models as they were originally intended, is that they are not descriptions of a data model per se. This is not to say that data modeling is not important, or that your model won’t have a similar shape as your data model; it will. But that is not the original point. In MVC as it was originally understood, a model is a list of subscribers. You can add yourself to that list, you can remove yourself from that list, and whenever a “value” changes, if you are on that list, you get a notification that the value has changed. You have a couple of different designs of these, depending on whether you want to send a current-state message as a notification on subscription, or just give everybody read access to the current state. The latter commits you to initializing your models in ways that indicate the absence or staleness of data (someone loads your app, you need to send out a network request to get a new thing) but also allows you to use variable scope to augment how much multiplexing and state tracking you need. Models vary from data models in having view-relevant data. So for example you switch from the type const urlList = new Model<UrlRow[]>([])
to the type type Fetching<x> = { state: "init" }
| { state: "loaded", data: x },
| { state: "fetching", staleData: x },
| { state: "fetch error", staleData: null | x }
const urlList = new Model<Fetching<UrlRow[]>>({
state: "init"
})
Notice that these Fetching indicator statuses are a part of the data model for the UI, not the underlying data model that exists at the database level.If this begins to feel a lot like React and Redux, that is because there is a shared lineage there. React originally made its splash as “the V in MVC” but its setState/state system, while it doesn't contain a subscriber list, effectively does something equivalent by insisting on destroying anything that has the old values and then superficially identifying things which appeared to remain the same from moment to moment, with the basic model then being a “subscription tree.” Redux of course takes this from being a tree to being something more generic by making the store global... I think that models should not be app-global the way that Redux likes (it does not want to solve the problem of multiplexing models, which is understandable but it turns out to be a much simpler problem than you'd think) and that the pattern of reducers is more verbose than one generally needs, but I love the time travel browser features that Redux gives me. Somehow Redux has encouraged abominations like redux-thunk which complect separate concerns into the same dispatch function unnecessarily. But the fundamental workings involve that same basic structure: a subscriber list. |
Could you clarify why you feel that redux-thunk is an "abomination"? What specific concerns do you have?
I wrote a post a while back that answered several concerns I'd seen expressed about using thunks [0], and my "Redux Fundamentals" workshop slides [1] have a section discussing why middleware like thunks are the right way to handle logic [2].
Also, what do you mean by "multiplexing models"?
[0] https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-th...
[1] https://blog.isquaredsoftware.com/2018/06/redux-fundamentals...
[2] https://blog.isquaredsoftware.com/presentations/workshops/re...