DocsCookbookCommunityGitHub →

Data context

With Symbiote.js you don't need any external state management library. It's easy to connect, but you really just don't need it in most cases.

All components created with Symbiote.js are present in some data context. Some of properties in that context are local and accessible for certain component only. Some of data could be received form the one of the parent components in document tree. Some of data could be received from the abstract data layers using unique keys. You can organize your application data flow with a high level of flexibility. Let's clarify what does it mean.

To initiate component's data context, use init$ property:

class MyComponent extends BaseComponent {
  init$ = {
    // Local component property initialization:
    myProp: 'some value',

    // Common data context property initialization:
    '*applicationBooleanProp': true,

    // Named context property initialization:
    'user-profile/name': 'John',
  }
}

$ - is for state

We use Proxy based interface to organize access to the data.

class MyComponent extends BaseComponent {
  initCallback() {
    this.$.myProp = 'My value';
    // ^ this will cause update for all subscribed entities
  }
}

To make synchronous multiple updates use set$:

class MyComponent extends BaseComponent {
  initCallback() {
    this.set$({
      myProp: 'new value',
      someOtherProp: true,
    });
  }
}

To get current property value:

class MyComponent extends BaseComponent {
  initCallback() {
    console.log(this.$.myProp);
    // or
    console.log(this.$['*someCommonProp']);
    // or
    console.log(this.$['my-named-data-ctx/prop']);
  }
}

Property subscription

class MyComponent extends BaseComponent {
  initCallback() {
    this.sub('propName', (val) => {
      console.log(val);
    });
    // ^ this subscription will be automatically removed on component destruction
  }
}

Local context properties

Local data context is accessible for certain component only. This is the simplest type of data interaction which is very similar to state manipulation approach in many other solutions. So you might be already know everything you need about it.

Hierarchical context properties

Every Symbiote component - is a Custom Element and represented in document tree as a one of it's elements. Every component could have a parent or child components. And every component is able to create common data context for it's own children or any other deep nested component.

To create common context for some DOM subtree manually, use ctx-name attribute:

<my-widget ctx-name="my-widget-ctx">
  <inner-block></inner-block>
</my-widget>

If context is not created manually with attribute, it will be created by top level component automatically.

Common context

For components placed at the same hierarchy level, it's possible to create common data context using same ctx-name value:

<first-component ctx-name="my-ctx"></first-component>

<second-component ctx-name="my-ctx"></second-component>

Now both of these components can read and publish values for the common property:

class FirstComponent extends BaseComponent {
  init$ = {
    '*commonProperty': true,
  }
}
FirstComponent.reg('first-component');

class SecondComponent extends BaseComponent {
  initCallback() {
    this.$['*commonProperty'] = false;
  }
}
SecondComponent.reg('second-component');

Named context

Named context - is abstract data context accessible with unique key:

import { Data } from '../symbiote/core/Data.js';

Data.registerNamedCtx('my-ctx-name', {
  count: 0,
  increment: () => {
    let ctx = Data.getNamedCtx('my-ctx-name');
    ctx.pub('count', ++ctx.read('count'));
  },
});

class MyComponent extends BaseComponent {}

MyComponent.template /*html*/ `
  <h2>Count: {{my-ctx-name/count}}</h2>
  <button set="onclick: my-ctx-name/increment">Click me!</button>
`;