Skip to content

Instantly share code, notes, and snippets.

@nicolashery nicolashery/db.js
Last active Aug 29, 2015

Embed
What would you like to do?
var merge = require('react/lib/merge');
var m = require('mori');
var toArray = function (val) {
if (!Array.isArray(val)) {
val = [val];
}
return val;
};
var Db = function(state) {
this._resetState(state);
this._watchers = [];
};
Db.prototype = merge(Db.prototype, {
_updateState: function (newState) {
this._state = newState;
this._states = m.conj(this.states, newState);
},
_resetState: function (state) {
state = state || m.hash_map();
this._state = state;
this._states = m.vector(this.state);
},
_notify: function(oldState, newState) {
this._watchers.forEach(function (w) {
w(oldState, newState);
});
},
_set: function(state, keys, value) {
var arrKeys = toArray(keys);
if (typeof value === 'function') {
return m.update_in(state, arrKeys, value);
}
else {
return m.assoc_in(state, arrKeys, value);
}
},
set: function (keys, value) {
var oldState = this._state;
var newState = this._set(this._state, keys, value);
this._updateState(newState);
this._notify(oldState, newState);
},
get: function (keys) {
if (typeof keys === 'string') {
return m.get(this._state, keys);
}
return m.get_in(this._state, keys);
},
transact: function(txData) {
var oldState = this._state;
var newState = this._state;
var self = this;
txData.forEach(function(tx) {
var keys = tx[0];
var value = tx[1];
newState = self._set(newState, keys, value);
});
this._updateState(newState);
this._notify(oldState, newState);
},
reset: function(newState) {
var oldState = this._state;
this._resetState(newState);
this._notify(oldState, newState);
},
snapshot: function() {
return this._state;
},
listen: function (watcher) {
this._watchers.push(watcher);
},
unlisten: function (watcher) {
this._watchers = this._watchers.filter(function (w) {
return w !== watcher;
});
}
});
var db = new Db();
db.set('user', m.hash_map('name', 'bob'));
console.log(m.clj_to_js(db.get('user'))); //-> {name: "bob"}
db.set(['user', 'name'], 'john');
console.log(m.clj_to_js(db.get('user'))); //-> {name: "john"}
db.set('user', function(user) {
return m.assoc(user, 'name', m.get(user, 'name').toUpperCase());
});
console.log(m.clj_to_js(db.get('user'))); //-> {name: "JOHN"}
console.log(m.clj_to_js(db.get(['user', 'name']))); //-> "JOHN"
var handler = function(oldState, newState) {
if (m.equals(m.get(oldState, 'user'), m.get(newState, 'user'))) {
return;
}
console.log('user changed to', m.clj_to_js(m.get(newState, 'user')));
};
db.listen(handler);
db.set(['user', 'name'], 'john'); //-> user changed to {name: "john"}
db.set('foo', 'bar'); //-> nothing
db.set(['user', 'name'], 'john'); //-> nothing
db.unlisten(handler);
db.set(['user', 'name'], 'bob'); //-> nothing
db.listen(handler);
db.transact([
['user', m.js_to_clj({name: 'mary'})],
[['user', 'name'], 'jenny']
]); //-> user changed to {name: "jenny"}
var React = require('react');
var m = require('mori');
var Db = require('./Db.js');
var DbMixin = function(db) {
return {
getInitialState: function() {
var state = {};
if (this.additionalState) {
state = this.additionalState();
}
for (var k in this.stateFromDb) {
state[k] = db.get(this.stateFromDb[k]);
}
return state;
},
componentDidMount: function() {
db.listen(this._refreshState);
},
componentWillUnmount: function() {
db.unlisten(this._refreshState);
},
shouldComponentUpdate: function(nextProps, nextState) {
var result = false;
if (this.additionalUpdateCheck) {
result = this.additionalUpdateCheck(nextProps, nextState);
}
for (var k in this.stateFromDb) {
result = result || !m.equals(this.state[k], nextState[k]);
}
return result;
},
_refreshState: function() {
if (!this.isMounted()) {
return;
}
var updates = {};
for (var k in this.stateFromDb) {
updates[k] = db.get(this.stateFromDb[k]);
}
this.setState(updates);
}
};
};
var User = React.createClass({
mixins: [DbMixin(db)],
stateFromDb: {
user: 'user'
},
render: function() {
console.log('render');
return React.DOM.div(null, "Name: ", React.DOM.strong(null, m.get(this.state.user, 'name')));
}
});
var db = new Db();
db.set('user', m.hash_map('name', 'bob'));
React.renderComponent(User(null), document.body); //-> render
db.set(['user', 'name'], 'john'); //-> render
db.set(['user', 'name'], 'john'); // -> nothing
db.transact([
['user', m.js_to_clj({name: 'mary'})],
[['user', 'name'], 'jenny']
]); //-> render (1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.