fastflux
Version:
Message driven reactive state management
115 lines (91 loc) • 3.23 kB
JavaScript
'use strict';
exports.__esModule = true;
exports.createSubscriber = createSubscriber;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _utilsIndexJs = require('../utils/index.js');
var _react = require('react');
var _observableStateJs = require('./observable/state.js');
var _observableStateJs2 = _interopRequireDefault(_observableStateJs);
/**
* Higher-order component that automatically subscribes to
* {@link ObservableState} props.
*
* @example
* let text = new ObservableState("Foo");
*
* class Label extends React.Component {
* render() {
* return <div>{this.props.text}</div>;
* }
* }
* Label = createSubscriber(Label);
*
* // Render <Label> with text "Foo"
* React.render(<Label text={text} />, mountPoint);
*
* // After 1 second change text to "Bar"
* setTimeout(() => text.emit("Bar"), 1000);
*
* @param {React.Component} component - the component to wrap
* @returns {React.Component}
*/
function createSubscriber(component) {
var wrapper = function wrapper(props, context) {
_react.Component.call(this, props, context);
this.normalProps = {};
this.observableProps = {};
this.updaters = {};
var state = {};
for (var k in this.props) {
var prop = this.props[k];
if (!_utilsIndexJs.isObservableState(prop)) this.normalProps[k] = prop;else {
this.observableProps[k] = prop;
state[k] = prop.getState();
}
}
this.state = state;
};
wrapper.prototype = Object.create(_react.Component.prototype, {
constructor: { value: wrapper },
componentWillMount: { value: function value() {
var _this = this;
var _loop = function (k) {
var observable = _this.observableProps[k];
var updater = _this.updaters[k] = function (state) {
var updated = {};
updated[k] = state;
_this.setState(updated);
};
observable.subscribe(updater);
};
for (var k in this.observableProps) {
_loop(k);
}
} },
componentWillUnmount: { value: function value() {
for (var k in this.updaters) {
this.observableProps[k].unsubscribe(this.updaters[k]);
delete this.updaters[k];
}
} },
componentWillReceiveProps: { value: function value(nextProps) {
for (var k in this.observableProps) {
if (nextProps[k] !== this.observableProps[k]) throw new Error("Cannot change an observable state prop once initialized. " + "To change the value, call setState");
}
for (var k in this.normalProps) {
if (nextProps[k] === void 0) delete this.normalProps[k];
}
for (var k in nextProps) {
var prop = nextProps[k];
if (!(k in this.observableProps)) {
if (!_utilsIndexJs.isObservableState(prop)) this.normalProps[k] = prop;else throw new Error("Cannot change non-observable prop to observable once initialized");
}
}
} },
render: { value: function value() {
return _react.createElement(component, _utilsIndexJs.assign({}, this.normalProps, this.state));
} }
});
return wrapper;
}
;