Versions Compared


  • This line was added.
  • This line was removed.
  • Formatting was changed.


The PropertyTree no longer uses the observable pattern of MobX (no longer uses MobX - YN). The intentions of this effort is to make Perspective more lightweight and performant (more lightweight, performant, and rely less on third-party libraries - YN). By removing MobX and following a simpler subscribe  and notify pattern (making use of a simpler subscription pattern, we've managed to reduce a considerable amount of overhead, resulting in a net increase in performance- YN) we can reduce a considerable amount of overhead, resulting in a net increase in performance. 

This (The removal of MobX - YN) means that components that are dereferencing nodes of a PropertyTree in MobX defined reactive functions (i.e. render, computed, reaction, autorun, etc.) can no longer expect that these reactive function will be triggered when the dereferenced node's value changes. The PropertyTree now makes use of a simpler subscribe and notify  pattern: (To subscribe to PropertyTree changes directly, use the `subscribe` method on the instance: -YN)

  • subscribe(listener: PropertyTreeChangeListener<unknown>): PropertyTreeChangeListenerDisposer - A public method used to subscribe a listener to any updates to the tree.  The listener takes a tree as an argument.  Implementers can use this to re-read from the tree and do whatever they would like with the new values.  Returns a disposer function that can be used by components to remove the listener from the tree's list of listeners in order to prevent memory leaks and no longer subscribe to changes.
  • notify(): void - A private method used internal to the tree which will notify all of the subscribed listeners. (Remove this. They don't need to know about it. - YN)
  • readObject(path: string, defaultValue = {}): PlainObject - A new PropertyTree read method. (This is not related, and should be mentioned in a separate thought.  Like, "in addition, the PropertyTree adds a new read method:" - YN)

By removing third party library dependencies from PropertyTree we open up further opportunities in performance improvement exploration. (Could probably be condensed and moved to the last line of the first paragraph - YN)


Introduced PropertyUtil, a named export of the perspective-client package. The namespace contains utility functions that are used by the PropertyTree to coerce Node values to a requested type. These are the inner workings of PropertyTree read methods. This was needed for components that would use the PropertyTree to read one or many nested properties of objects. Using utilities such as isNumber and isString were found to be too strict since they do not coerce the value.  PropertyUtil was created to prevent regressions and maintain existing behavior when evaluating nested properties of an object.

As meitioned (mentioned - YN)PropertyUtil contains several utility functions that coerce values. (Literally logic used by the PropertyTree when performing reads - YN) For example:

Code Block
function getBooleanOrDefault(value, defaultValue) {
    if (typeof value === 'boolean') {
        // return if its already a boolean
    } else if (typeof value === 'number') {
        // return if it's not 0
    } else if (typeof value === 'string') {
        // return if the string is 'true'
    } else {
        // return the default


The shape of ComponentProps has changed. A component's props no longer contain instances of PropertyTree at the root level.  To access trees, use must go through the corresponding ComponentStore or store prop. 

For example (NEW - YN):'value', newValue) 

instead of (OLD - YN):

this.props.props.write(‘value’, newValue)`)


Two changes were made to ComponentMeta. First, the function getViewClass  has been renamed to getViewComponent  and now is (remove 'and now is' I suppose - YN).

getViewComponent(): PComponent -  Renamed from getViewClass  to be more inclusive of functional components. Expected return type is PComponent  and no longer React.ReactType .



The examples on the rest of the page look like Kotlin. Is that correct? Not certain if that's worth stating for module/component authors.  - Paul S. 

(Not Kotlin, but Typescript - YN)

Code Block
export class MyComponentMeta implements ComponentMeta {
    // Renamed from getViewClass. Returns a PComponent 
    // which is either a class or functional Perspective component.
    getViewComponent(): PComponent {
        return Label;

    // Reducer function whose return value gets mapped to 
    // 'this.props.props' for class components or 'props.props'
    // for functional components
    getPropsReducer(tree: PropertyTree): MyComponentProps {
        return {
            value: tree.readString("value"),

    getComponentType(): string {
        return ID;

    getDefaultSize(): SizeObject {
        return { width: 50, height: 50 };