Component

To create a component:

  1. Create a subclass that inherits from Component class and define build method.
  2. Instantiate the subclass

To display the component in UI, use mountComponent function.

Here is an example of Counter component. The value of count starts with 0. When the Click Me button is clicked, the value of count increases by 1 and the new value is displayed in the UI.

counter.js :

import Component from './node_modules/@xylem-js/xylem-js/dom/Component.js';
import createStore from './node_modules/@xylem-js/xylem-js/core/createStore.js';
import mountComponent from './node_modules/@xylem-js/xylem-js/dom/mountComponent.js';
import parseHTML from './node_modules/@xylem-js/xylem-js/dom/parseHTML.js';

class Counter extends Component
{
	build()
	{
		const count$ = createStore(0);

		return parseHTML([
			'<div>',
			[
				'Count: ',
				count$,
			],
			'</div>',
			'<div>',
			[
				'<button>', {
					'@click': () => count$._(count$._() + 1),
				},
				[
					'Click Me',
				],
				'</button>',
			],
			'</div>',
		]);
	}
}

mountComponent(new Counter(), document.getElementById('app-container'));

JSX version:

counter-jsx.tsx :

import Component from './node_modules/@xylem-js/xylem-js/dom/Component.js';
import mountComponent from './node_modules/@xylem-js/xylem-js/dom/mountComponent.js';

class Counter extends Component
{
	build()
	{
		const count$ = createStore(0);

		return <>
			<div>
				Current count: {}
				{ count$ }
			</div>
			<div>
				<button
					on:click={() => count$._(count$._() + 1)}
				>
					Click
				</button>
			</div>
		</>;
	}
}

mountComponent(new Counter(), document.getElementById('app-container')!);

Lifecycle events of component

Component has following lifecycle events:

  1. afterSetup
  2. afterAttachToDom
  3. beforeDetachFromDom

The lifecycle events are available as property of the component with the same name.

afterSetup

This is called after virtual DOM tree is created, before DOM nodes are available. This is useful to modify components like modifying class attribute. However, it is rarely necessary.

For Server Side Rendered component, this is called in both server side and client side.

afterAttachToDom

This is called after DOM tree is attached to the document. The subscribers are called immediately, so any changes made to the DOM nodes is immediately reflected without flash of previous state.

This is useful for asynchronous operation like setTimeout(), setInterval(), fetch(), XMLHttpRequest:send() etc.

For Server Side Rendered component, this is not called in server side but during hydration in client side.

beforeDetachFromDom

This is called before DOM tree is removed from the document.

This is useful for cleanup of operation done in afterAttachToDom like clearTimeout(), clearInterval(), AbortController:abort() , XMLHttpRequest:abort() etc.

Example

The example below shows Clock component that shows current date-time and update every second. In afterAttachToDom, setInterval() is called and in beforeDetachFromDom, clearInterval() is called.

clock.js :

import Component from './node_modules/@xylem-js/xylem-js/dom/Component.js';
import createStore from './node_modules/@xylem-js/xylem-js/core/createStore.js';
import mountComponent from './node_modules/@xylem-js/xylem-js/dom/mountComponent.js';
import parseHTML from './node_modules/@xylem-js/xylem-js/dom/parseHTML.js';

class Clock extends Component
{
	build()
	{
		const currentDateTime$ = createStore('');
		let intervalID;

		this.afterAttachToDom.subscribe(() => {
			currentDateTime$._(new Date() + '');
			intervalID = setInterval(() => {
				currentDateTime$._(new Date() + '');
			}, 1000);
		});

		this.beforeDetachFromDom.subscribe(() => {
			clearInterval(intervalID);
		});

		return parseHTML([
			'<div>',
			[
				'Current date-time: ',
				currentDateTime$,
			],
			'</div>',
		]);
	}
}

mountComponent(new Clock(), document.getElementById('app-container'));