UNPKG

dugong

Version:

Minimal State Container for React Apps using RxJS

159 lines (135 loc) 6.11 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.connect = exports.removeAllListeners = exports.getLastState = exports.getStore = exports.updateStore = exports.createStore = undefined; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** * Minimal Store Management using rx * * @author Avraam Mavridis <avr.mav@gmail.com> * */ var _rx = require('rx'); var _pick = require('lodash/pick'); var _pick2 = _interopRequireDefault(_pick); var _react = require('react'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var stateSubject = new _rx.BehaviorSubject(); var noop = function noop() { return void 0; }; /** * Custom Error * @param { Object } settings */ var StoreError = function StoreError(settings) { this.name = 'RxStoreError'; this.message = settings.message; this.context = settings.context; this.component = this.context.constructor.name; Error.captureStackTrace(this, this.constructor); }; /** * Determines if the wrapped component is a React Component * @param {Class or Function} target */ var isReactComponent = function isReactComponent(target, func) { if (!target || !(target.prototype instanceof _react.Component)) { throw new StoreError({ message: 'connect() should wrap a React Component', context: _react.Component.prototype }); } func.call(this, target); }; var createStore = exports.createStore = function createStore(initialState) { return stateSubject.onNext(_extends({}, initialState)); }; var updateStore = exports.updateStore = function updateStore(newState) { return stateSubject.onNext(_extends({}, stateSubject.value, newState)); }; var getStore = exports.getStore = function getStore() { return stateSubject; }; var getLastState = exports.getLastState = function getLastState() { return stateSubject.value; }; /** * Remove all listeners */ var removeAllListeners = exports.removeAllListeners = function removeAllListeners() { return stateSubject.dispose(); }; /** * React decorator, decorates a React component * @return {ReactComponent} */ var connect = exports.connect = function connect() { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return function (target) { return isReactComponent(target, function (target) { var obj = Object.create(target.prototype); var willMount = obj.componentWillMount || noop; var willUnmount = obj.componentWillUnmount || noop; var onComplete = obj.onComplete || noop; var onError = obj.onError || function (stg) { throw new StoreError(stg); }; /** * It is called when the Subjects stops pushing values */ target.prototype.onComplete = function onComp() { onComplete.call(this); }; /** * It is called when an error happens on the store * @param {Error object} err */ target.prototype.onError = function onErr(err) { /* isStopped is passed by rx and means that the stream has stopped due to an error, in that case err.message is not so meaningfull and its better to pass the stack as message, that can could change in the future */ var message = this.isStopped ? err.stack : err.message; var settings = _extends({}, err, { message: message || 'An error in your store.', context: this }); onError.call(this, settings); }; /** * Set the listener on componentWillMount * Listener will setState */ target.prototype.componentWillMount = function componentWillMount() { var _this = this; this.__subscription = stateSubject.map(function (state) { return args.length ? (0, _pick2.default)(state, args) : state; }).subscribe(function (state) { return _this.setState(state); }, this.onError, this.onComplete); willMount.call(this); }; /** * Remove subscriber on componentWillUnmount */ target.prototype.componentWillUnmount = function componentWillUnmount() { this.unsubscribe(); willUnmount.call(this); }; /** * Provide an unsubscribe function to the underline component */ target.prototype.unsubscribe = function unsubscribe() { try { this.__subscription.dispose(); } catch (err) { this.onError(err); } }; return target; }); }; };