From 99460d3718dd198ff787619eea6f78b78c39faa4 Mon Sep 17 00:00:00 2001 From: JeffJiang Date: Tue, 27 Aug 2019 05:54:48 +0800 Subject: [PATCH] feat(core): bean force update (#40) * feat(core): supports bean force update * chore(npm): version 0.1.3-beta --- package.json | 2 +- src/core/ForceUpdate.ts | 1 + src/core/StatedBeanContainer.ts | 38 +++++++++++++++++++++++++++++---- src/core/index.ts | 1 + src/event/Event.ts | 10 +++++---- src/hooks/useStatedBean.ts | 9 ++++---- 6 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 src/core/ForceUpdate.ts diff --git a/package.json b/package.json index 33ff88f9b..9c0d18011 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stated-bean", - "version": "0.1.2-RC.4", + "version": "0.1.3-beta", "repository": "git@github.com:mjolnirjs/stated-bean.git", "license": "MIT", "main": "dist/cjs", diff --git a/src/core/ForceUpdate.ts b/src/core/ForceUpdate.ts new file mode 100644 index 000000000..01676f714 --- /dev/null +++ b/src/core/ForceUpdate.ts @@ -0,0 +1 @@ +export const ForceUpdate = Symbol('stated-bean-force-update'); diff --git a/src/core/StatedBeanContainer.ts b/src/core/StatedBeanContainer.ts index afc44655e..acdb8ad03 100644 --- a/src/core/StatedBeanContainer.ts +++ b/src/core/StatedBeanContainer.ts @@ -4,6 +4,7 @@ import { getMetadataStorage } from '../metadata'; import { StatedBeanApplication } from './StatedBeanApplication'; import { EffectContext } from './EffectContext'; +import { ForceUpdate } from './ForceUpdate'; export class StatedBeanContainer extends Event { private readonly _parent?: StatedBeanContainer; @@ -75,11 +76,12 @@ export class StatedBeanContainer extends Event { return; } + this.addForceUpdate(bean, beanMeta); + const fields = beanMeta.statedFields || []; const observers = (fields || []).map(field => this.observeBeanField(bean, field, beanMeta), ); - await Promise.all(observers); if ( @@ -91,6 +93,32 @@ export class StatedBeanContainer extends Event { } } + addForceUpdate(bean: T, beanMeta: StatedBeanMeta) { + const self = this; + Object.defineProperty(bean, ForceUpdate, { + value: function(field: keyof T & string) { + if (bean[field] === undefined) { + return; + } + const fieldMeta = (beanMeta.statedFields || []).find( + f => f.name === field, + ); + if (fieldMeta === undefined) { + return; + } + const effect = self.createEffectContext( + bean[field], + bean, + beanMeta, + fieldMeta, + bean[field], + ); + + self.emit(bean, effect); + }, + }); + } + async observeBeanField( bean: any, fieldMeta: StatedFieldMeta, @@ -123,11 +151,13 @@ export class StatedBeanContainer extends Event { value, ); - bean[proxyField] = effect.getValue(); + bean[proxyField] = value; self.application.interceptStateChange(effect).then(() => { - bean[proxyField] = effect.getValue(); + if (effect.getValue() !== value) { + bean[proxyField] = effect.getValue(); + } // console.log(bean.constructor.name + '_changed'); - self.emit(beanMeta.target, effect); + self.emit(bean, effect); }); }, get() { diff --git a/src/core/index.ts b/src/core/index.ts index 04c7eec0b..8d5744212 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -3,3 +3,4 @@ export * from './StatedBeanApplication'; export * from './StatedBeanContainer'; export * from './StatedBeanFactory'; export * from './StatedBeanScope'; +export * from './ForceUpdate'; diff --git a/src/event/Event.ts b/src/event/Event.ts index b80bf1ffd..bfc3649df 100644 --- a/src/event/Event.ts +++ b/src/event/Event.ts @@ -1,14 +1,16 @@ +import { ClassType } from '../types'; + type EventListenFn = (...args: any) => void; -type EventTypes = WeakMap; +type EventTypes = WeakMap, EventListenFn[]>; export class Event { events: EventTypes = new WeakMap(); - on(type: Function, cb: EventListenFn) { + on(type: InstanceType, cb: EventListenFn) { this.events.set(type, (this.events.get(type) || []).concat(cb)); } - emit(type: Function, ...data: any) { + emit(type: InstanceType, ...data: any) { if (this.events.has(type)) { this.events.get(type)!.forEach(cb => { cb(...data); @@ -16,7 +18,7 @@ export class Event { } } - off(type: Function, cb: EventListenFn) { + off(type: InstanceType, cb: EventListenFn) { if (this.events.has(type)) { this.events.set(type, this.events.get(type)!.filter(c => c !== cb)); } diff --git a/src/hooks/useStatedBean.ts b/src/hooks/useStatedBean.ts index 668df9869..59627f88a 100644 --- a/src/hooks/useStatedBean.ts +++ b/src/hooks/useStatedBean.ts @@ -48,9 +48,6 @@ export function useStatedBean( container.register(type); } - if (container !== undefined) { - container.on(type, beanChangeListener); - } return container; }); @@ -59,7 +56,11 @@ export function useStatedBean( } const [bean] = useState(() => { - return container.getBean>(type); + const bean = container.getBean>(type); + if (container !== undefined) { + container.on(bean, beanChangeListener); + } + return bean; }); if (bean === undefined) {