Volatile state
MST models primarily aid in storing persistable state. State that can be persisted, serialized, transferred, patched, replaced, etc. However, sometimes you need to keep track of temporary, non-persistable state. This is called volatile state in MST. Examples include promises, sockets, DOM elements, etc. - state which is needed for local purposes as long as the object is alive.
Volatile state (which is also private) can be introduced by creating variables inside any of the action initializer functions.
Volatile is preserved for the life-time of an object, and not reset when snapshots are applied, etc. Note: The life-time of an object depends on proper reconciliation.
The following is an example of an object with volatile state. Note: Volatile state here is used to track a XHR request, and clean up resources when it is disposed. Without volatile state, this kind of information would need to be stored in an external WeakMap or something similar.
const Store = types.model({
todos: types.array(Todo),
state: types.enumeration("State", ["loading", "loaded", "error"])
})
.actions(self => {
const pendingRequest = null // a Promise
function afterCreate() {
self.state = "loading"
pendingRequest = someXhrLib.createRequest("someEndpoint")
}
function beforeDestroy() {
// abort the request, no longer interested
pendingRequest.abort()
}
return {
afterCreate,
beforeDestroy
}
})
Some Tips
- Note that multiple
action
calls can be chained. This makes it possible to create multiple closures with their own protected volatile state. - Although in the above example, the
pendingRequest
could be initialized directly in the action initializer, it is recommended to do this in theafterCreate
hook, which will only execute once the entire instance has been set up. (There might be many action and property initializers for a single type.) - It is possible to share volatile state between views and actions by using
extend
..extend
works like a combination of.actions
and.views
and should return an object with aactions
andviews
field:
const Todo = types.model({}).extend(self => {
let localState = 3
return {
views: {
get x() {
return localState
}
},
actions: {
setX(value) {
localState = x
}
}
}
})