# Overview
# Mosx object
Mosx object can be created in 2 ways:
- by
@mx.Object
decorator - by extending Mosx class
// wrap with class decorator
@mx.Object
class State {
// property decorator
@mx clients = new Map()
// ...
}
// extending Mosx class
class Item extends Mosx {
@mx name = "abc"
// ...
}
// inheritance is also supported
class Child extends Item {
// ...
}
TIP
Instanses of State, Item and Child classes will be Mosx object
console.log(new State() instanceof Mosx) // true
console.log(new Item() instanceof Mosx) // true
console.log(new Child() instanceof Mosx) // true
# Supported types
- primitive types: number, string, boolean
- complex types: embeded object (Mosx), array, map
@mx.Object
class Item {
// simple types: string, number, boolen
@mx name = "abc"
@mx id = 123
@mx bool = false
// complex types: object, array, map
@mx obj = new Item() // must be Mosx instance
@mx arr = new Array<Item>()
@mx map = new Map<string, Item>()
}
# Snapshots
Snapshots are the immutable, structurally shared, representation of Mosx object (and it's children).
Basically, when a change is performed over a Mosx object then a new immutable snapshot can be generated via Mosx.getSnapshot
method.
Getting the snapshot out of any Mosx object is as easy as this:
@mx.Object
class Item {
@mx name = "abc"
@mx id = 123
@mx bool = false
}
const item = new Item()
// get snapshot of item
console.log(Mosx.getSnapshot(item))
// { name: "abc", id: 123, bool: false }
# Change tracker
Every change of Mosx state can be tracked. First you need to create tracker and then subscribe for patches:
const tracker = Mosx.createTracker(state)
const disposer = tracker.onPatch((patch: IEncodedJsonPatch, obj: any, state: State) => {
// ...
console.log(patch)
})
A patch object has this structure:
export interface IEncodedJsonPatch {
op: "replace" | "remove" | "add"
path: Path
value?: any // value is not available for remove operations
oldValue?: any // only if reversible enabled
encoded?: Buffer // only if serializer used
}
# Computed and Observable properies
Computed property can be tracked also if it depends on any @mx
property (including @mx.oservable
). Use @mx.computed
decorator to wrap computed property.
@mx.Object
class Item {
// computed property
@mx.computed get flag() {
return this.mobx ? "Computed value" : ""
}
// observable property
@mx.observable public mobx = true
}
const item = new Item()
// get snapshot of item
console.log(Mosx.getSnapshot(item))
// { flag: 'Computed value' }
// update observable property
item.mobx = false
// get updated snapdhot of item
console.log(Mosx.getSnapshot(item))
// { flag: '' }
Observable properties are hidden for tracker and snapshots
TIP
@mx.observable === mobx.observable
# Private objects and properties
By default all @mx
objects/properties are public and visible for all listeners. If it is required to manage visibility of objects/properies you need to make them private.
Use @mx.Object.private
decorator for private objects:
@mx.Object.private
class PrivateItem {
...
}
Use @mx.private
decorator for private properties and @mx.computed.private
decorator for private computed properties:
@mx.Object
class Item {
// public property
@mx name = "abc"
// private property
@mx.private value = 100
// private computed property
@mx.computed.private get flag() {
// ...
}
}
const item = new Item()
// get snapshot of item
console.log(Mosx.getSnapshot(item))
// { name: 'abc' }
Private objects and properties are not visible for tracker and in snapshots without access tags. Access for private objects and properties are described in Visibility management.
# Visiblity management
# Access tags
Access tags can be added to any Mosx object. All listeners with one of this tag can see all private properties of Mosx object. To manage access tags of object use addTag, deleteTag, getTags
methods:
@mx.Object
class Item {
// public property
@mx name = "abc"
// private property
@mx.private value = 100
}
const item = new Item()
// add access tags to object
Mosx.addTag(item, ["123", "234"])
// get snapshot of item with access tag
console.log(Mosx.getSnapshot(item, "123"))
// { name: 'abc', value: 100 }
console.log(Mosx.getSnapshot(item, "234"))
// { name: 'abc', value: 100 }
// delete one of tags
Mosx.deleteTag(item, "123")
console.log(Mosx.getSnapshot(item, "123"))
// { name: 'abc' }
console.log(Mosx.getSnapshot(item, "234"))
// { name: 'abc', value: 100 }
console.log(Mosx.getTags(item))
// Set(1) {"234"}
# Virtual objects tree (advanced)
Every Mosx object has virtual Mosx parent and inherits parent tags and tracker. By default parent of all Mosx objects are root state Object. To manage virtual objects tree use setParent
method:
@mx.Object
class State {
@mx players = new Array()
@mx objects = new Map()
}
class Player extends Mosx {
@mx.private id: string
@mx name: string
constructor(id: string, name: string) {
super(null, id) // setTag for player
this.id = id
this.name = name
}
}
@mx.Object.private
class Item {
@mx created = Date.now()
}
// create state and players
const state = new State()
const p1 = new Player("1", "John")
const p2 = new Player("2", "Tony")
// create 2 items and set p1 as parent
const i1 = new Item()
Mosx.setParent(i1, p1)
// Mosx.new - short alias
const i2 = Mosx.new(Item, p1)()
// add players and items to state
state.players.push(p1, p2)
state.objects.set("item1", i1)
state.objects.set("item2", i2)
// check state for player p1
console.log(Mosx.getSnapshot(state, p1.id))
// {
// players: [ { id: '1', name: 'John' }, { name: 'Tony' } ],
// objects: { item1: { created: 1603317890537 }, item2: { created: 1603317890538 }}
// }
// check state for player p2
console.log(Mosx.getSnapshot(state, p2.id))
// {
// players: [ { name: 'John' }, { id: '2', name: 'Tony' } ],
// objects: { item1: undefined, item2: undefined }
// }
← Introduction Mosx API →