diff --git a/src/components/excel/Excel.ts b/src/components/excel/Excel.ts index 92bda52..d856a30 100644 --- a/src/components/excel/Excel.ts +++ b/src/components/excel/Excel.ts @@ -2,6 +2,7 @@ import { Store } from '../../core/createStore'; import { $, Dom } from '../../core/dom'; import { Emitter } from '../../core/Emitter'; import { ExcelComponent } from '../../core/ExcelComponent'; +import { StoreSubscriber } from '../../core/StoreSubscriber'; interface ExcelOptionsType { components: any[], @@ -13,12 +14,14 @@ export class Excel { components: any[]; emitter: Emitter; store: Store; + subscriber: StoreSubscriber; constructor(selector: string, options: ExcelOptionsType) { this.$el = $(selector); this.components = options.components; this.emitter = new Emitter(); this.store = options.store; + this.subscriber = new StoreSubscriber(this.store); console.log(`Created new Excel class in ${selector} with options: ${options}`); } @@ -46,10 +49,13 @@ export class Excel { render() { this.$el.append(this.getRoot()); + + this.subscriber.subscribeComponents(this.components); this.components.forEach(component => component.init()); } destroy() { + this.subscriber.unsubscribeFromStore(); this.components.forEach(component => component.destroy()); } } diff --git a/src/components/formula/Formula.ts b/src/components/formula/Formula.ts index 0886020..215ab89 100644 --- a/src/components/formula/Formula.ts +++ b/src/components/formula/Formula.ts @@ -10,6 +10,7 @@ export class Formula extends ExcelComponent { super($root, { listeners: ['input', 'keydown'], name: 'Formula', + subscribe: ['currentText'], ...options, }); } @@ -26,16 +27,13 @@ export class Formula extends ExcelComponent { this.formulaInput = this.$root.find('#formula-input'); - // this.$on('table:input', text => { - // this.formulaInput.text = text; - // }); this.$on('table:select-cell', text => { this.formulaInput.text = text; }); + } - this.$subscribe(state => { - this.formulaInput.text = state.currentText; - }); + storeChanged({ currentText = '' }) { + this.formulaInput.text = currentText; } onInput(event: Event) { diff --git a/src/core/ExcelComponent.ts b/src/core/ExcelComponent.ts index 3356336..bce3712 100644 --- a/src/core/ExcelComponent.ts +++ b/src/core/ExcelComponent.ts @@ -1,4 +1,4 @@ -import { ActionType, StateType, SubscribeType } from '../redux/types'; +import { ActionType, SubscribeType } from '../redux/types'; import { Store } from './createStore'; import { DomListener } from './DomListener'; import { Emitter } from './Emitter'; @@ -6,6 +6,7 @@ import { Emitter } from './Emitter'; interface ExcelComponentClass { toHTML: () => string; prepare: () => void; + storeChanged?: (args: any) => void; } type OptionsType = { @@ -13,13 +14,15 @@ type OptionsType = { name: string; emitter?: Emitter; store: Store; + subscribe: string[], }; -export class ExcelComponent extends DomListener implements ExcelComponentClass { +export abstract class ExcelComponent extends DomListener implements ExcelComponentClass { name: string; emitter: Emitter; store: Store; storeSub: SubscribeType; + subscribe: string[]; private unsubscribers: ((args?: any) => any)[]; constructor($root: any, options: OptionsType) { @@ -27,6 +30,8 @@ export class ExcelComponent extends DomListener implements ExcelComponentClass { this.name = options?.name; this.emitter = options?.emitter; this.store = options?.store; + this.subscribe = options?.subscribe; + this.unsubscribers = []; this.prepare(); } @@ -52,8 +57,12 @@ export class ExcelComponent extends DomListener implements ExcelComponentClass { this.store.dispatch(action); } - $subscribe(fn: (state?: StateType) => void) { - this.storeSub = this.store.subscribe(fn); + storeChanged(args?: any) { + console.log('CHANGE STORE: ', args); + } + + isWatching(key: string) { + return this.subscribe?.includes(key); } init() { diff --git a/src/core/StoreSubscriber.ts b/src/core/StoreSubscriber.ts new file mode 100644 index 0000000..408b388 --- /dev/null +++ b/src/core/StoreSubscriber.ts @@ -0,0 +1,35 @@ +import { StateType } from '../redux/types'; +import { Store } from './createStore'; +import { isEqual } from './utils'; + +export class StoreSubscriber { + sub: any; + prevState: StateType; + + constructor(private store: Store) { + this.sub = null; + this.prevState = {}; + } + + subscribeComponents(components: any[]) { + this.prevState = this.store.getState(); + + this.sub = this.store.subscribe((state: StateType) => { + Object.keys(state).forEach(key => { + if (!isEqual(this.prevState[key], state[key])) { + components.forEach(component => { + if (component.isWatching(key)) { + const changes = { [key]: state[key] }; + component.storeChanged(changes); + } + }); + } + }); + this.prevState = this.store.getState(); + }); + } + + unsubscribeFromStore() { + this.sub.unsubscribe(); + } +} diff --git a/src/core/createStore.ts b/src/core/createStore.ts index 022f2c0..f8de14e 100644 --- a/src/core/createStore.ts +++ b/src/core/createStore.ts @@ -37,6 +37,6 @@ export class Store { } getState() { - return this.state; + return JSON.parse(JSON.stringify(this.state)); } } diff --git a/src/core/utils.ts b/src/core/utils.ts index f560953..2e37cca 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -11,3 +11,11 @@ export function storage(key: string, data: any = null): any { return true; } + +export function isEqual(a: any, b: any) { + if (typeof a === 'object' && typeof b === 'object') { + return JSON.stringify(a) === JSON.stringify(b); + } + + return a === b; +}