Last active
June 13, 2018 05:28
-
-
Save wspl/02c62cfc7f9d5d368126752e75029c95 to your computer and use it in GitHub Desktop.
Tronx - Mobx for Electron
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type TronxHandler = () => void | |
interface TronxStore { | |
value: any, | |
handlers: Set<TronxHandler> | |
} | |
class TronxTable { | |
propertyMap = new Map<object, Map<PropertyKey, TronxStore>>() | |
refMap = new Map<object, TronxStore>() | |
constructor() {} | |
get(target: any, key: PropertyKey): TronxStore { | |
if (!this.propertyMap.has(target)) { | |
this.propertyMap.set(target, new Map<PropertyKey, TronxStore>()) | |
} | |
if (!this.propertyMap.get(target).has(key)) { | |
this.propertyMap.get(target).set(key, { | |
handlers: new Set<TronxHandler>(), | |
value: null | |
}) | |
} | |
return this.propertyMap.get(target).get(key) | |
} | |
getRef(obj: any): TronxStore { | |
if (!this.refMap.has(obj)) { | |
this.refMap.set(obj, { | |
handlers: new Set<TronxHandler>(), | |
value: null | |
}) | |
} | |
return this.refMap.get(obj) | |
} | |
} | |
export interface ITronx { | |
table: TronxTable | |
depCollector: IDependenciesCollector | |
arrayMap: Map<object, Array<any>> | |
} | |
interface IDependenciesCollector { | |
isCollecting: boolean | |
relatedHandler: TronxHandler | |
begin(handler: TronxHandler) | |
finish() | |
} | |
const dependenciesCollector: IDependenciesCollector = { | |
isCollecting: false, | |
relatedHandler: null, | |
begin(handler: TronxHandler) { | |
this.isCollecting = true | |
this.relatedHandler = handler | |
}, | |
finish() { | |
this.isCollecting = false | |
this.relatedHandler = null | |
} | |
} | |
const tronx: ITronx = { | |
table: new TronxTable(), | |
depCollector: dependenciesCollector, | |
arrayMap: new Map<object, Array<any>>() | |
} | |
global['tronx'] = tronx | |
function isPureObject(obj: any): boolean { | |
return obj.constructor === Object | |
} | |
function isArray(obj: any): boolean { | |
return obj instanceof Array | |
} | |
function smartProxify<T extends object>(target: T, key: PropertyKey, value: any): boolean { | |
if (typeof value === 'object') { | |
if (isPureObject(value)) { | |
target[key] = proxify(value) | |
} else { | |
target[key] = proxify(value, true) | |
} | |
return true | |
} | |
return false | |
} | |
function proxify<T extends object>(target: T, shallow: boolean = false): T { | |
if (!shallow) { | |
Object.entries(target).forEach(([key, value]) => { | |
smartProxify(target, key, value) | |
}) | |
} | |
if (isArray(target)) { | |
(target as Array<any>).forEach((value, key) => { | |
smartProxify(target, key, value) | |
}) | |
} | |
return new Proxy(target, { | |
get: (target, key) => { | |
// console.log('get', target, key) | |
if (tronx.depCollector.isCollecting) { | |
const store = shallow ? tronx.table.getRef(target) : tronx.table.get(target, key) | |
store.handlers.add(tronx.depCollector.relatedHandler) | |
} | |
return target[key] | |
}, | |
set: (target, key, value, receiver) => { | |
// console.log(target, key, value) | |
if (!smartProxify(target, key, value)) { | |
target[key] = value | |
} | |
const store = shallow ? tronx.table.getRef(target) : tronx.table.get(target, key) | |
store.handlers.forEach(handler => handler()) | |
return true | |
} | |
}) | |
} | |
export function Observable(target: any, key: string) { | |
Object.defineProperty(target, key, { | |
get: () => { | |
const store = tronx.table.get(target, key) | |
if (tronx.depCollector.isCollecting) { | |
store.handlers.add(tronx.depCollector.relatedHandler) | |
} | |
return store.value | |
}, | |
set: (newVal) => { | |
const store = tronx.table.get(target, key) | |
if (newVal && typeof newVal === 'object') { | |
if (isPureObject(newVal)) { | |
store.value = proxify(newVal) | |
} else { | |
store.value = proxify(newVal, true) | |
} | |
} else { | |
store.value = newVal | |
} | |
store.handlers.forEach(handler => handler()) | |
}, | |
enumerable : true, | |
configurable : true | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { remote } from 'electron' | |
import { ITronx, TronxHandler } from './Tronx.main' | |
const tronx: ITronx = remote.getGlobal('tronx') | |
function autorun(handler: TronxHandler) { | |
tronx.depCollector.begin(handler) | |
handler() | |
tronx.depCollector.finish() | |
} | |
export function Observer() { | |
return function(target) { | |
const targetCWM = target.prototype.componentWillMount | |
target.prototype.componentWillMount = function() { | |
targetCWM && targetCWM.call(this) | |
autorun(() => { | |
console.log('autorun') | |
this.render() | |
this.forceUpdate() | |
}) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment