UNPKG

react-pure-events

Version:

A HOC wrapper that makes events props passed to React PureComponents pure

167 lines (127 loc) 6.44 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); 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; }; 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; }; }(); exports.wrapPureEventProps = wrapPureEventProps; exports.guardPureEventProps = guardPureEventProps; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _hoistNonReactMethods = require('hoist-non-react-methods'); var _hoistNonReactMethods2 = _interopRequireDefault(_hoistNonReactMethods); var _omit = require('lodash/omit'); var _omit2 = _interopRequireDefault(_omit); var _flatten = require('lodash/flatten'); var _flatten2 = _interopRequireDefault(_flatten); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: 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; } // @todo add tests // - Test that the various decorator formats work // - test against the react version used by react-native function makeDecorator(events, guard) { events = (0, _flatten2.default)(events); return function (BaseComponent) { // @todo Hoist methods var Wrapper = function (_Component) { _inherits(Wrapper, _Component); function Wrapper() { var _ref; var _temp, _this, _ret; _classCallCheck(this, Wrapper); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Wrapper.__proto__ || Object.getPrototypeOf(Wrapper)).call.apply(_ref, [this].concat(args))), _this), _this._setMainRef = function (ref) { _this._mainRef = ref; }, _this._eventHandlers = {}, _temp), _possibleConstructorReturn(_this, _ret); } // @todo Is it worth it to wrap propTypes now that they are deprecated? _createClass(Wrapper, [{ key: '_eventHandlerFor', value: function _eventHandlerFor(name) { var _this2 = this; if (!this._eventHandlers[name]) { this._eventHandlers[name] = function () { for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } if (typeof _this2.props[name] === 'function') { return _this2.props[name].apply(null, args); } }; } return this._eventHandlers[name]; } }, { key: 'render', value: function render() { var otherProps = (0, _omit2.default)(this.props, events); var eventProps = {}; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = events[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var event = _step.value; var value = this.props[event]; if (guard || typeof value === 'function') { eventProps[event] = this._eventHandlerFor(event); } else if (event in this.props) { eventProps[event] = value; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return _react2.default.createElement(BaseComponent, _extends({ ref: this._setMainRef }, otherProps, eventProps)); } }]); return Wrapper; }(_react.Component); Wrapper.displayName = 'wrapPureEventProps(' + (BaseComponent.displayName || BaseComponent.name || 'Component') + ')'; return (0, _hoistNonReactMethods2.default)(Wrapper, BaseComponent, function (component) { return component._mainRef; }); }; } /** * Wraps a PureComponent with a HOC that replaces a set of event props * with functions that call the event prop, but if passed are the same on every * render() call even if the actual function passed to the HOC changes. * * This guarantees that even if a caller uses `onEvent={() => {}}` which causes * a new function instance to be passed every render the PureComponent will always * receive the same prop and remain purely optimized. */ function wrapPureEventProps() { for (var _len3 = arguments.length, events = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { events[_key3] = arguments[_key3]; } return makeDecorator(events, false); } /** * Does the same as @wrapPureEventProps, but also guarantees that if an event prop * is not a function (not passed or invalid) a noop function will be passed instead. */ function guardPureEventProps() { for (var _len4 = arguments.length, events = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { events[_key4] = arguments[_key4]; } return makeDecorator(events, true); }