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)