Skip to content

Commit e9bd358

Browse files
committed
docs (easyComp): comment the render function logic
1 parent 388dfa7 commit e9bd358

File tree

6 files changed

+831
-535
lines changed

6 files changed

+831
-535
lines changed

dist/clock.js

Lines changed: 103 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -14523,8 +14523,10 @@ Object.defineProperty(exports, "__esModule", {
1452314523
value: true
1452414524
});
1452514525
exports.default = autoBind;
14526+
// do not bind these, they should not be directly invoked or passed as callbacks by the user
1452614527
var reactInternals = new Set(['constructor', 'render', 'componentWillMount', 'componentDidMount', 'componentWillReceiveProps', 'shouldComponentUpdate', 'componentWillUpdate', 'componentDidUpdate', 'componentWillUnmount']);
1452714528

14529+
// bind the methods from proto to the passed context object and assign them to the context
1452814530
function autoBind(context, proto, isReact) {
1452914531
var _iteratorNormalCompletion = true;
1453014532
var _didIteratorError = false;
@@ -27058,7 +27060,7 @@ var _get = function get(object, property, receiver) { if (object === null) objec
2705827060

2705927061
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; }; }();
2706027062

27061-
exports.default = easyCompHOC;
27063+
exports.default = easyComp;
2706227064

2706327065
var _react = __webpack_require__(25);
2706427066

@@ -27076,91 +27078,129 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
2707627078

2707727079
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; }
2707827080

27079-
var OBSERVED_RENDER = Symbol('observed render');
27080-
var IS_DIRECT_RENDER = Symbol('is direct render');
27081-
var RENDER_RESULT = Symbol('render result');
27081+
var REACTIVE_RENDER = Symbol('reactive render');
2708227082

27083-
function easyCompHOC(WrappedComp) {
27084-
if (typeof WrappedComp !== 'function') {
27085-
throw new TypeError('easyComp expects a component class or function as argument.');
27083+
function easyComp(Comp) {
27084+
if (typeof Comp !== 'function') {
27085+
throw new TypeError('easyComp expects a component as argument.');
2708627086
}
2708727087

27088-
if ((!WrappedComp.prototype || !WrappedComp.prototype.render) && !WrappedComp.isReactClass && !_react.Component.isPrototypeOf(WrappedComp)) {
27089-
var renderer = WrappedComp;
27090-
WrappedComp = function (_Component) {
27091-
_inherits(WrappedComp, _Component);
27088+
// wrap stateless components in a class
27089+
if (isStatelessComp(Comp)) {
27090+
Comp = statelessToStatefulComp(Comp);
27091+
} else if (hasComponentShouldUpdate(Comp)) {
27092+
// shouldComponentUpdate is optimized by easyState, overwriting it would add zero or less value
27093+
throw new Error('easyState optimizes shouldComponentUpdate, do not implement it.');
27094+
}
27095+
27096+
return toReactiveComp(Comp);
27097+
}
27098+
27099+
function isStatelessComp(Comp) {
27100+
return !(Comp.prototype && Comp.prototype.render) && !_react.Component.isPrototypeOf(Comp);
27101+
}
27102+
27103+
function statelessToStatefulComp(StatelessComp) {
27104+
var _class, _temp;
27105+
27106+
return _temp = _class = function (_Component) {
27107+
_inherits(StatefulComp, _Component);
27108+
27109+
function StatefulComp() {
27110+
_classCallCheck(this, StatefulComp);
27111+
27112+
return _possibleConstructorReturn(this, (StatefulComp.__proto__ || Object.getPrototypeOf(StatefulComp)).apply(this, arguments));
27113+
}
27114+
27115+
_createClass(StatefulComp, [{
27116+
key: 'render',
27117+
2709227118

27093-
function WrappedComp() {
27094-
_classCallCheck(this, WrappedComp);
27119+
// call the original function component inside the render method
2709527120

27096-
return _possibleConstructorReturn(this, (WrappedComp.__proto__ || Object.getPrototypeOf(WrappedComp)).apply(this, arguments));
27121+
// proxy react specific static variables to the stateful component
27122+
// from the stateless component
27123+
value: function render() {
27124+
return StatelessComp.call(this, this.props, this.context);
2709727125
}
27126+
}]);
2709827127

27099-
_createClass(WrappedComp, [{
27100-
key: 'render',
27101-
value: function render() {
27102-
return renderer.call(this, this.props, this.context);
27103-
}
27104-
}]);
27128+
return StatefulComp;
27129+
}(_react.Component), _class.displayName = StatelessComp.displayName || StatelessComp.name, _class.contextTypes = StatelessComp.contextTypes, _class.propTypes = StatelessComp.propTypes, _class.defaultProps = StatelessComp.defaultProps, _temp;
27130+
}
2710527131

27106-
return WrappedComp;
27107-
}(_react.Component);
27108-
WrappedComp.displayName = renderer.displayName || renderer.name;
27109-
WrappedComp.contextTypes = renderer.contextTypes;
27110-
WrappedComp.propTypes = renderer.propTypes;
27111-
WrappedComp.defaultProps = renderer.defaultProps;
27112-
}
27132+
function hasComponentShouldUpdate(Comp) {
27133+
return typeof Comp.prototype.shouldComponentUpdate === 'function';
27134+
}
2711327135

27114-
if (typeof WrappedComp.prototype.shouldComponentUpdate === 'function') {
27115-
throw new Error('Do not implement shouldComponentUpdate, easyState already optimizes it for you!');
27116-
}
27136+
function toReactiveComp(Comp) {
27137+
var _class2, _temp2;
2711727138

27118-
return function (_WrappedComp) {
27119-
_inherits(EasyCompWrapper, _WrappedComp);
27139+
// return a HOC which overwrites render, shouldComponentUpdate and componentWillUnmount
27140+
// it decides when to run the new reactive methods and when to proxy to the original methods
27141+
return _temp2 = _class2 = function (_Comp) {
27142+
_inherits(EasyHOC, _Comp);
2712027143

27121-
function EasyCompWrapper(props) {
27122-
_classCallCheck(this, EasyCompWrapper);
27144+
// proxy react specific static variables to the HOC from the component
27145+
function EasyHOC(props) {
27146+
_classCallCheck(this, EasyHOC);
2712327147

27124-
var _this2 = _possibleConstructorReturn(this, (EasyCompWrapper.__proto__ || Object.getPrototypeOf(EasyCompWrapper)).call(this, props));
27148+
// auto bind non react specific original methods to the component instance
27149+
var _this2 = _possibleConstructorReturn(this, (EasyHOC.__proto__ || Object.getPrototypeOf(EasyHOC)).call(this, props));
2712527150

27126-
(0, _autoBind2.default)(_this2, WrappedComp.prototype, true);
27151+
(0, _autoBind2.default)(_this2, Comp.prototype, true);
27152+
27153+
// turn the state into an observable object, which triggers rendering on mutations
2712727154
_this2.state = (0, _observerUtil.observable)(_this2.state);
2712827155
return _this2;
2712927156
}
2713027157

27131-
_createClass(EasyCompWrapper, [{
27158+
_createClass(EasyHOC, [{
2713227159
key: 'render',
2713327160
value: function render() {
2713427161
var _this3 = this;
2713527162

27136-
if (!this[OBSERVED_RENDER]) {
27137-
this[OBSERVED_RENDER] = function () {
27138-
if (_this3[IS_DIRECT_RENDER]) {
27139-
_this3[RENDER_RESULT] = _get(EasyCompWrapper.prototype.__proto__ || Object.getPrototypeOf(EasyCompWrapper.prototype), 'render', _this3).call(_this3);
27163+
// if it is the first direct render from react call there is no reactive render yet
27164+
if (!this[REACTIVE_RENDER]) {
27165+
var result = void 0;
27166+
// create a reactive render, which is automatically called by easyState on relevant state and store mutations
27167+
// the passed function is executed right away synchronously once by easyState
27168+
this[REACTIVE_RENDER] = (0, _observerUtil.observe)(function () {
27169+
// if it is the first (synchronous) execution, call the original component's render
27170+
// this is necessary because forceUpdate can not be called synchronously inside render functions
27171+
if (!_this3[REACTIVE_RENDER]) {
27172+
result = _get(EasyHOC.prototype.__proto__ || Object.getPrototypeOf(EasyHOC.prototype), 'render', _this3).call(_this3);
2714027173
} else {
27141-
_get(EasyCompWrapper.prototype.__proto__ || Object.getPrototypeOf(EasyCompWrapper.prototype), 'forceUpdate', _this3).call(_this3);
27174+
// if it is a later reactive, asynchronous execution - triggered by easyState - forceUpdate the original component
27175+
// this is necessary, because calling render would require the result to be returned
27176+
// which is not possible from this asynchronous context
27177+
_get(EasyHOC.prototype.__proto__ || Object.getPrototypeOf(EasyHOC.prototype), 'forceUpdate', _this3).call(_this3);
2714227178
}
27143-
};
27179+
});
27180+
// return the result from super.render() inside the reactive render on the first render execution
27181+
return result;
27182+
} else {
27183+
// return the original component's render result on direct calls from react
27184+
return _get(EasyHOC.prototype.__proto__ || Object.getPrototypeOf(EasyHOC.prototype), 'render', this).call(this);
2714427185
}
27186+
}
2714527187

27146-
this[IS_DIRECT_RENDER] = true;
27147-
this[OBSERVED_RENDER] = (0, _observerUtil.observe)(this[OBSERVED_RENDER]);
27148-
this[IS_DIRECT_RENDER] = false;
27188+
// react should trigger updates on prop changes, while easyState handles state changes
2714927189

27150-
return this[RENDER_RESULT];
27151-
}
2715227190
}, {
2715327191
key: 'shouldComponentUpdate',
27154-
value: function shouldComponentUpdate(nextProps, nextState) {
27192+
value: function shouldComponentUpdate(nextProps) {
2715527193
var props = this.props;
2715627194

2715727195
var keys = Object.keys(props);
2715827196
var nextKeys = Object.keys(nextProps);
2715927197

27198+
// component should update if the number of its props changed
2716027199
if (keys.length !== nextKeys.length) {
2716127200
return true;
2716227201
}
2716327202

27203+
// component should update if any of its props changed value
2716427204
var _iteratorNormalCompletion = true;
2716527205
var _didIteratorError = false;
2716627206
var _iteratorError = undefined;
@@ -27173,6 +27213,8 @@ function easyCompHOC(WrappedComp) {
2717327213
return true;
2717427214
}
2717527215
}
27216+
27217+
// do not let react update the comp otherwise, leave state triggered updates to easyState
2717627218
} catch (err) {
2717727219
_didIteratorError = true;
2717827220
_iteratorError = err;
@@ -27193,15 +27235,19 @@ function easyCompHOC(WrappedComp) {
2719327235
}, {
2719427236
key: 'componentWillUnmount',
2719527237
value: function componentWillUnmount() {
27196-
if (_get(EasyCompWrapper.prototype.__proto__ || Object.getPrototypeOf(EasyCompWrapper.prototype), 'componentWillUnmount', this)) {
27197-
return _get(EasyCompWrapper.prototype.__proto__ || Object.getPrototypeOf(EasyCompWrapper.prototype), 'componentWillUnmount', this).call(this);
27238+
// clean up memory used by easyState
27239+
(0, _observerUtil.unobserve)(this[REACTIVE_RENDER]);
27240+
27241+
// also call user defined componentWillUnmount to allow the user
27242+
// to clean up additional memory
27243+
if (_get(EasyHOC.prototype.__proto__ || Object.getPrototypeOf(EasyHOC.prototype), 'componentWillUnmount', this)) {
27244+
_get(EasyHOC.prototype.__proto__ || Object.getPrototypeOf(EasyHOC.prototype), 'componentWillUnmount', this).call(this);
2719827245
}
27199-
(0, _observerUtil.unobserve)(this[OBSERVED_RENDER]);
2720027246
}
2720127247
}]);
2720227248

27203-
return EasyCompWrapper;
27204-
}(WrappedComp);
27249+
return EasyHOC;
27250+
}(Comp), _class2.displayName = Comp.displayName || Comp.name, _class2.contextTypes = Comp.contextTypes, _class2.propTypes = Comp.propTypes, _class2.defaultProps = Comp.defaultProps, _temp2;
2720527251
}
2720627252

2720727253
/***/ }),
@@ -27407,9 +27453,11 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
2740727453

2740827454
function easyStore(store) {
2740927455
if ((typeof store === 'undefined' ? 'undefined' : _typeof(store)) !== 'object' || store === null) {
27410-
throw new TypeError('easyStore expects an object as argument.');
27456+
throw new TypeError('easyStore expects an object as argument');
2741127457
}
2741227458

27459+
// create an observable object from the passed store
27460+
// and bind all of its methods to the created observable
2741327461
var observableStore = (0, _observerUtil.observable)(store);
2741427462
(0, _autoBind2.default)(observableStore, store, false);
2741527463
return observableStore;

0 commit comments

Comments
 (0)