diff --git a/src/core/HNode.ts b/src/core/HNode.ts index 6469300..22422aa 100644 --- a/src/core/HNode.ts +++ b/src/core/HNode.ts @@ -27,15 +27,22 @@ export type HProps

= { children: unknown[]; }); +export type HCallback

= + (this: HNode, props: HProps

, store: S, context: C) => T; + +export type EffectCallback

= + HCallback | void>; + export interface HDesc

{ defaultProps?: Partial

; defaultStore?: Partial>; storeHandlers?: PartialHandlers, S>; + effects?: EffectCallback[]; state?: Array>; context?: Array>; - init?: (this: HNode, props: HProps

, store: S, context: C) => void; - render: (this: HNode, props: HProps

, store: S, context: C) => unknown; - clear?: (this: HNode, props: HProps

, store: S, context: C) => void; + init?: HCallback; + render: HCallback; + clear?: HCallback; catch?: (this: HNode, err: any, props: HProps

, store: S, context: C) => unknown; } @@ -52,6 +59,7 @@ export interface HNode

[]; err?: unknown; } diff --git a/src/core/HUI.ts b/src/core/HUI.ts index b4fabe9..d9ac800 100644 --- a/src/core/HUI.ts +++ b/src/core/HUI.ts @@ -1,4 +1,4 @@ -import { HProps as _HProps, HDesc as _HDesc, HNode as _HNode } from "./HNode"; +import { HProps as _HProps, HDesc as _HDesc, HNode as _HNode, HCallback as _HCallback, EffectCallback as _EffectCallback } from "./HNode"; import { registry, define, HType as _HType } from "./registry"; import { _assign, _Infinity, _requestAnimationFrame } from "../utils/refCache"; import { Store as _Store, createStore, HandlerMap as _HandlerMap, Setter as _Setter, SetterRecord as _SetterRecord, StoreType as _StoreType, StoreHandlers as _StoreHandlers, PartialHandlers as _PartialHandlers, EmptyStore as _EmptyStore } from "./Store"; @@ -43,6 +43,8 @@ HUI.cmp = compare; export namespace HUI { export type HProps

= _HProps

; + export type HCallback

= _HCallback; + export type EffectCallback

= _EffectCallback; export type HDesc

= _HDesc; export type HNode

= _HNode; diff --git a/src/core/initComponent.ts b/src/core/initComponent.ts index 9aff5e9..53e1ee4 100644 --- a/src/core/initComponent.ts +++ b/src/core/initComponent.ts @@ -1,15 +1,16 @@ -import { HNode } from "./HNode"; +import { HNode, HCallback, HProps } from "./HNode"; import { Store } from "./Store"; import { supply } from "../utils/helpers"; +import { _Boolean } from "../utils/refCache"; -export const initComponent = function initCom(hNode: HNode, store: Store) { +export const initComponent = function initCom

(hNode: HNode, store: S) { const { props, ctx } = hNode, desc = hNode.desc!, - { defaultProps, defaultStore, storeHandlers, state, context, init } = desc; + { defaultProps, defaultStore, storeHandlers, state, context, init, effects } = desc; if (defaultProps) { - supply(props, defaultProps); + supply(props, defaultProps as Partial>); } hNode.sto = store; @@ -17,18 +18,22 @@ export const initComponent = function initCom(hNode: HNode, store: Store) { store.setSome(defaultStore); } if (state) { - hNode.sto.bind(hNode, state); + hNode.sto.bind(hNode as unknown as HNode, state); } if (storeHandlers) { store.handleSome(storeHandlers); } if (context) { - ctx!.bind(hNode, context); + ctx!.bind(hNode as unknown as HNode, context); } if (init) { init.call(hNode, props, store, ctx!); } + if (effects) { + hNode.eff = effects.map(effect => effect.call(hNode, props, store, ctx!)).filter(_Boolean) as HCallback[]; + } + }; \ No newline at end of file diff --git a/src/ext/Portal.ts b/src/ext/Portal.ts index 369dbcf..ed9712b 100644 --- a/src/ext/Portal.ts +++ b/src/ext/Portal.ts @@ -19,32 +19,39 @@ export interface PortalStore { export const Portal = define, EmptyStore>('HUI.Portal', { - init: function port_init(props, store) { - store.set('p', props.parent || _document.body); - store.set('f', HUI(Fragment, _null, props.children)); - }, + effects: [ + function ptl_eff(props, store) { - render: function port_render(props, store, context) { - renderToDOM(store.get('f'), { - parent: store.get('p'), - owner: this, - context - }); - }, + const { parent = _document.body } = props, + fragment = HUI(Fragment, _null, props.children); - clear: function port_clear(props, store) { + store.set('p', parent); + store.set('f', fragment); - const fragment = store.get('f')!, - { ownNode, nodes } = fragment; + return function ptl_clr() { - clear(fragment); + const { ownNode, nodes } = fragment; - nodes!.forEach(node => { - ownNode!.removeChild(node); - }); + clear(fragment); + + nodes!.forEach(node => { + ownNode!.removeChild(node); + }); + + nodes!.length = 0; - nodes!.length = 0; + }; + } + ], + + + render: function ptl_render(props, store, context) { + renderToDOM(store.get('f'), { + parent: store.get('p'), + owner: this, + context + }); } }); diff --git a/src/utils/clear.ts b/src/utils/clear.ts index 9812469..5ddfbe8 100644 --- a/src/utils/clear.ts +++ b/src/utils/clear.ts @@ -11,12 +11,22 @@ export const clear = function clr(hNode: HNode) { if (desc) { - if (desc.clear) { - try { - desc.clear.call(hNode, props, hNode.sto!, hNode.ctx!); - } catch (err) { - _console.error(err); + const { sto, ctx } = hNode; + + try { + + if (hNode.eff) { + hNode.eff.forEach(effCanceller => { + effCanceller.call(hNode, props, sto!, ctx!); + }); } + + if (desc.clear) { + desc.clear.call(hNode, props, sto!, ctx!); + } + + } catch (err) { + _console.error(err); } } else { diff --git a/test/src/Timer.tsx b/test/src/Timer.tsx index 0611b6e..89bf584 100644 --- a/test/src/Timer.tsx +++ b/test/src/Timer.tsx @@ -4,7 +4,6 @@ interface TimerProps { interface TimerStore { time: number; - timer: any; } type TimerStoreHandlers = { @@ -19,17 +18,24 @@ const Timer = HUI.define, start: 0 }, + effects: [ + function (props, store) { + const timer = store.trigger('setInterval', 1000); + return () => { + clearInterval(timer); + }; + } + ], + storeHandlers: { setInterval(interval) { const timer = setInterval(this.inc, interval, 'time'); - this.set('timer', timer); return timer; } }, init(props, store) { store.set('time', props.start!); - store.set('timer', store.trigger('setInterval', 1000)); }, render(props, store) { @@ -38,10 +44,6 @@ const Timer = HUI.define, Time: {store.get('time')} ); - }, - - clear(props, store) { - clearInterval(store.get('timer')); } }); \ No newline at end of file