lore-hook-connect
Version:
A lore hook that generates dialogs using Bootstrap
154 lines (116 loc) • 5 kB
JavaScript
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({...})
*
*/
;