Using Proxy as Object.Observe for App State
by nathanlogan
CSS
#console {
padding: 10px;
border-bottom: 1px solid #ccc;
background-color: #eee;
max-height: 15em;
overflow: auto;
line-height: 1.5;
}
JavaScript
// (just for ease of viewing console)
console={_createConsole:function(){var pre = document.createElement('pre'); pre.setAttribute('id', 'console');document.body.insertBefore(pre, document.body.firstChild);return pre;},log: function (message) {var pre = document.getElementById("console") || console._createConsole(); pre.textContent += ['>', message, '\n'].join(' ')}}
// our native "observable"
let observable = function(baseObject, callback, deleteCallback) {
var proxyDefinition = {
set: function(obj, prop, value) {
obj[prop] = value // default behavior to store the value
// arrays get "set" twice: 1) value 2) to update "length"
// - this eliminates #2 from showing up in our callback
if (!Array.isArray(obj) || prop !== 'length') {
callback(value)
}
return true
},
deleteProperty: function (oTarget, sKey) {
if (sKey in oTarget) {
delete oTarget[sKey]
deleteCallback()
return true
}
return false
}
}
// this is all well and good, so long as you don't care about supporting IE
// - http://caniuse.com/#search=proxy
// - https://kangax.github.io/compat-table/es6/#test-Proxy
return new Proxy(baseObject, proxyDefinition)
}
// ////////////////////////////////////////////////////////////////////////
// really easy to set up a store
let store = {
appInfo: observable({}, function(val){console.log('appInfo change: ' + val)}),
users: observable(
[],
function(val){console.log('users change: ' + val.firstName)},
function(){console.log('DELETED user')}
)
}
// ////////////////////////////////////////////////////////////////////////
// make changes and see if they're reflected
store.appInfo.token = 123
store.appInfo.environment = 'dev'
store.users.push({firstName: 'johnny'})
store.users.push({firstName: 'jim'})
store.users.pop()
store.users.push({firstName: 'sally'})
store.users.push({firstName: 'erik'})
console.log('Number of users: ' + store.users.length)