Skip to content

Instantly share code, notes, and snippets.

@wspl
Last active June 13, 2018 05:28
Show Gist options
  • Save wspl/02c62cfc7f9d5d368126752e75029c95 to your computer and use it in GitHub Desktop.
Save wspl/02c62cfc7f9d5d368126752e75029c95 to your computer and use it in GitHub Desktop.
Tronx - Mobx for Electron
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
})
}
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