immreact
Version:
Use react classes with an immstruct structure
233 lines (173 loc) • 7.04 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _immstruct2 = require('immstruct');
var _immstruct3 = _interopRequireDefault(_immstruct2);
var _immutable = require('immutable');
var _immutable2 = _interopRequireDefault(_immutable);
var _eventemitter = require('eventemitter3');
var _eventemitter2 = _interopRequireDefault(_eventemitter);
var _flux = require('flux');
var _constants = require('./constants');
var _constants2 = _interopRequireDefault(_constants);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _state = Symbol('state');
/**
* @class
* Holds data representing the current state of the application
*/
var State = function (_Dispatcher) {
_inherits(State, _Dispatcher);
/**
* @constructs
* A default namespace can be passed in here
* @param key <String> if key is not a string it will be interpreted as initial state
* @param initialState <Object> _optional_ defaults to {}
*/
function State(key) {
var initialState = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
_classCallCheck(this, State);
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(State).call(this));
_this.onSwap = function (o, n, k) {
if (!o) {
_this.onUpdate();
return;
}
if (o && n) {
// Check that a change really did happen
if (!_immutable2.default.is(o.getIn(k), n.getIn(k))) {
_this.onUpdate();
}
}
};
if (typeof key !== 'string') {
initialState = key;
key = _constants2.default.ROOT;
}
// Patch over an emitter
_eventemitter2.default.call(_this);
Object.assign(_this, _eventemitter2.default.prototype);
// Private state immstruct structure
_this[_state] = (0, _immstruct3.default)(key, _defineProperty({}, _constants2.default.COMPONENTS, {}));
_this.create(key, initialState);
// Use animation frame so that quick mutations to the tree are batched
// this[ _state ].on( 'swap', this.onSwap )
_this[_state].on('next-animation-frame', _this.onSwap);
return _this;
}
/**
* For now just triggered an update to call the listener
*/
_createClass(State, [{
key: 'start',
value: function start() {
this.onUpdate();
}
/**
* update function passed back the state tree
*/
}, {
key: 'onUpdate',
value: function onUpdate() {
this.emit('update', this);
}
/**
* Check for a change and emit an update when one occurs
*/
}, {
key: 'create',
/**
* Creates a new root level immutable and returns a ref to it
* @param key <String> _required_
* @param value <Object> _optional_ defaults to {}
*/
value: function create(key) {
var value = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
if (!key) {
throw new Error('No key specified when creating new state root');
}
// @TODO should check if key already exists
this[_state].cursor().update(function (cursor) {
return cursor.merge(_defineProperty({}, key, value));
});
return this[_state].reference(key);
}
/**
* Grabs a fresh cursor to the data structure
* @param args <Array>|<String> specify structure keyPath to grab
*/
}, {
key: 'cursor',
value: function cursor(args) {
if (!args) {
return this[_state].cursor();
}
if (typeof args === 'string') {
return this[_state].cursor(args);
}
return this[_state].cursor([].concat(_toConsumableArray(args)));
}
/**
* Returns the dereferenced value for read-only access
* @param args <Array>|<String> specify structure keyPath to grab
*/
}, {
key: 'get',
value: function get(args) {
if (!args) {
return this[_state].cursor().deref();
}
if (typeof args === 'string') {
return this[_state].cursor(args).deref();
}
return this[_state].cursor([].concat(_toConsumableArray(args))).deref();
}
}, {
key: 'reference',
value: function reference(args) {
if (!args) {
return this[_state].reference();
}
if (typeof args === 'string') {
return this[_state].reference(args);
}
return this[_state].reference([].concat(_toConsumableArray(args)));
}
/**
* Returns a JSON string to save
*/
}, {
key: 'save',
value: function save() {
try {
return JSON.stringify(this[_state].cursor().toJSON());
} catch (err) {
throw new Error(err);
}
}
/**
* Loads a JSON string into the current state
*/
}, {
key: 'load',
value: function load(state) {
try {
// this[ _state ].cursor().update( cursor => {
// return cursor.merge( JSON.parse( state ) )
// })
this[_state].cursor().merge(JSON.parse(state));
} catch (err) {
throw new Error(err);
}
}
}]);
return State;
}(_flux.Dispatcher);
exports.default = State;
;