UNPKG

lore-hook-connect

Version:

A lore hook that generates dialogs using Bootstrap

154 lines (116 loc) 5 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = function (actions, blueprints, reducerActionMap) { // provide getState with a copy of lore so it can access reducer-action map var getState = (0, _getState3.default)(actions, blueprints, reducerActionMap); return function connect(select) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return function (DecoratedComponent) { var displayName = 'Connect(' + (0, _getDisplayName2.default)(DecoratedComponent) + ')'; return (0, _createReactClass2.default)({ displayName: displayName, contextTypes: _lodash2.default.merge({ store: _storeShape2.default.isRequired }, options.contextTypes), getInitialState: function getInitialState() { // provide a decorator over getState that will force data to be fetched on // mount if desired var initialState = this.selectState(this.props, this.context, function getStateOnMount(state, stateKey, params) { var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; return getState(state, stateKey, params, _lodash2.default.assign({}, options, { force: options.forceFetchOnMount })); }); this.nextState = initialState; return {}; }, shouldComponentUpdate: function shouldComponentUpdate(nextProps) { var nextState = this.selectState(nextProps, this.context, getState); this.nextState = nextState; return true; }, componentDidMount: function componentDidMount() { this.isMounted = true; if (!options.subscribe) { return; } this.unsubscribe = this.context.store.subscribe(function () { var nextState = this.selectState(this.props, this.context, getState); // There's no guarantee the component will still be mounted, when this // callback is invoked, so we need to check before updating state if (this.isMounted) { this.setState(nextState); } }.bind(this)); }, componentWillUnmount: function componentWillUnmount() { this.isMounted = false; if (this.unsubscribe) { this.unsubscribe(); } }, selectState: function selectState(props, context, getState) { var state = context.store.getState(); var slice = select(getState.bind(null, state), props, context); (0, _invariant2.default)(_lodash2.default.isPlainObject(slice), 'The return value of `select` prop must be an object. Instead received %s.', slice); return slice; }, render: function render() { return _react2.default.createElement(DecoratedComponent, _lodash2.default.assign({ ref: 'decoratedComponent' }, this.nextState, this.props)); } }); }; }; }; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _createReactClass = require('create-react-class'); var _createReactClass2 = _interopRequireDefault(_createReactClass); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant); var _storeShape = require('./utils/storeShape'); var _storeShape2 = _interopRequireDefault(_storeShape); var _getDisplayName = require('./utils/getDisplayName'); var _getDisplayName2 = _interopRequireDefault(_getDisplayName); var _getState2 = require('./getState'); var _getState3 = _interopRequireDefault(_getState2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* eslint no-shadow: "off" */ /* eslint react/no-is-mounted: "warn" */ /* eslint react/prefer-es6-class: "off" */ module.exports = exports['default']; /** * Decorator for React components that allows the component to specify what data they need * and will automatically fetch that data if it doesn't exist. * * @param select: function(getState, props, context){...} * @param options: {subscribe: true} * @returns Function to pass to the component to be decorated * * Example usage: * * Scenario 1: If the component doesn't need to be subscribed to changes in the store (which * is the typical scenario) just pass in one argument; the state function and the component: * * connect(function(getState, props, context){ * return { * user: getState('user.current') * } * })(createReactClass({...})) * * Scenario 2: If the component does need to be subscribed to changes in the store, pass in * two arguments; the state function and options. * * connect(function(getState, props, context){ * return { * user: getState('user.current') * } * }, { * subscribe: true * })(createReactClass({...}) * */