References and identifiers
References and identifiers are first-class concepts in MST. This makes it possible to declare references, and keep the data normalized in the background, while you interact with it in a denormalized manner.
const Todo = types.model({
id: types.identifier(),
title: types.string
})
const TodoStore = types.model({
todos: types.array(Todo),
selectedTodo: types.reference(Todo)
})
// create a store with a normalized snapshot
const storeInstance = TodoStore.create({
todos: [{
id: "47",
title: "Get coffee"
}],
selectedTodo: "47"
})
// because `selectedTodo` is declared to be a reference, it returns the actual Todo node with the matching identifier
console.log(storeInstance.selectedTodo.title)
// prints "Get coffee"
Identifiers
- Each model can define zero or one
identifier()
properties - The identifier property of an object cannot be modified after initialization
- Each identifiers / type combination should be unique within the entire tree
- Identifiers are used to reconcile items inside arrays and maps - wherever possible - when applying snapshots
- The
map.put()
method can be used to simplify adding objects that have identifiers to maps - The primary goal of identifiers is not validation, but reconciliation and reference resolving. For this reason, identifiers cannot be defined or updated after creation. If you want to check if some value just looks as an identifier, without providing the above semantics, use something like:
types.refinement(types.string, v => v.match(/someregex/))
Tip:
If you know the format of the identifiers in your application, leverage
types.refinement
to actively check this. For example, the following definition enforces that identifiers ofCar
always start with the stringCar_
:
const Car = types.model("Car", { id: types.identifier(types.refinement(types.string, identifier => identifier.indexOf("Car_") === 0)) })
References
References are defined by mentioning the type they should resolve to. The targeted type should have exactly one attribute of the type identifier()
. References are looked up through the entire tree, but per type. So identifiers need to be unique in the entire tree.