UNPKG

@sampettersson/constate

Version:

Yet another React state management library that lets you work with local state and scale up to global state with ease

489 lines (387 loc) 14.2 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var React = require('react'); var Context = React.createContext({ state: {} }); var Consumer = Context.Consumer; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _extends() { _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; }; return _extends.apply(this, arguments); } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } var mapWith = function mapWith(map, transform) { return Object.keys(map).reduce(function (final, key) { var _objectSpread2; return _objectSpread({}, final, (_objectSpread2 = {}, _objectSpread2[key] = transform(map[key], key), _objectSpread2)); }, {}); }; var mapSetStateToActions = function mapSetStateToActions(setState, actionMap) { return mapWith(actionMap, function (action, type) { return function () { return setState(action.apply(void 0, arguments), undefined, type); }; }); }; var mapStateToSelectors = function mapStateToSelectors(state, selectorMap) { return mapWith(selectorMap, function (selector) { return function () { return selector.apply(void 0, arguments)(state); }; }); }; var mapPropsToEffects = function mapPropsToEffects(getEffectProps, effectMap) { return mapWith(effectMap, function (effect, type) { return function () { return effect.apply(void 0, arguments)(getEffectProps(type)); }; }); }; // _ is a temporary fix for eslint parser var parseUpdater = function parseUpdater(updaterOrState, state) { return typeof updaterOrState === "function" ? updaterOrState(state) : updaterOrState; }; var InnerContainer = /*#__PURE__*/ function (_React$Component) { _inheritsLoose(InnerContainer, _React$Component); function InnerContainer(props) { var _this; _this = _React$Component.call(this, props) || this; _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "state", _this.props.initialState); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "ignoreState", false); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "unmount", undefined); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getEffectProps", function (type) { var _this$props = _this.props, context = _this$props.context, state = _this$props.state; return { state: context && state ? state : _this.state, setState: function setState(u, c) { return _this.handleSetState(u, c, type); } }; }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleSetState", function (updater, callback, type) { var _this$props2 = _this.props, context = _this$props2.context, setContextState = _this$props2.setContextState; var prevState; var updaterFn = function updaterFn(state) { prevState = state; return parseUpdater(updater, state); }; var callbackFn = function callbackFn() { var _this$props3 = _this.props, _this$props3$state = _this$props3.state, state = _this$props3$state === void 0 ? _this.state : _this$props3$state, onUpdate = _this$props3.onUpdate; if (onUpdate && _this.ignoreState !== state) { onUpdate(_objectSpread({}, _this.getEffectProps("onUpdate"), { prevState: prevState, type: type })); } if (callback) callback(); }; if (context && setContextState) { setContextState(context, updaterFn, callbackFn, type); } else { // @ts-ignore _this.setState(updaterFn, callbackFn); } }); var _context = props.context, _setContextState = props.setContextState, _state = props.state, initialState = props.initialState; if (_context && _setContextState && !_state) { _setContextState(_context, function (currentState) { return Object.assign({}, initialState, currentState); }, undefined, "initialState"); } return _this; } var _proto = InnerContainer.prototype; _proto.componentDidMount = function componentDidMount() { var _this2 = this; var _this$props4 = this.props, context = _this$props4.context, mountContainer = _this$props4.mountContainer, onMount = _this$props4.onMount; var mount = function mount() { return onMount && onMount(_this2.getEffectProps("onMount")); }; if (context && mountContainer) { this.unmount = mountContainer(context, mount); } else if (!context) { mount(); } }; _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { var _this3 = this; var _this$props5 = this.props, context = _this$props5.context, stateFromProps = _this$props5.state; var nextStateFromProps = nextProps.state, shouldUpdate = nextProps.shouldUpdate; var couldUpdate = true; if (context && stateFromProps && nextStateFromProps && shouldUpdate) { couldUpdate = shouldUpdate({ state: stateFromProps, setState: function setState(u, c) { return _this3.handleSetState(u, c, "shouldUpdate"); }, nextState: nextStateFromProps }); this.ignoreState = !couldUpdate && nextStateFromProps; } else if (!context && shouldUpdate) { couldUpdate = shouldUpdate({ state: this.state, setState: function setState(u, c) { return _this3.handleSetState(u, c, "shouldUpdate"); }, nextState: nextState }); this.ignoreState = !couldUpdate && nextState; } return couldUpdate; }; _proto.componentWillUnmount = function componentWillUnmount() { var _this4 = this; var _this$props6 = this.props, context = _this$props6.context, onUnmount = _this$props6.onUnmount; var unmount = function unmount() { return onUnmount && onUnmount(_this4.getEffectProps("onUnmount")); }; if (this.unmount) { this.unmount(unmount); } else if (!context) { unmount(); } }; _proto.render = function render() { var _this$props7 = this.props, state = _this$props7.state, children = _this$props7.children, actions = _this$props7.actions, selectors = _this$props7.selectors, effects = _this$props7.effects; var childrenProps = Object.assign({}, state || this.state, actions && mapSetStateToActions(this.handleSetState, actions), selectors && mapStateToSelectors(state || this.state, selectors), effects && mapPropsToEffects(this.getEffectProps, effects)); return children(childrenProps); }; return InnerContainer; }(React.Component); // eslint-disable-next-line react/prefer-stateless-function, react/no-multi-comp _defineProperty(InnerContainer, "defaultProps", { initialState: {} }); var Container = /*#__PURE__*/ function (_React$Component2) { _inheritsLoose(Container, _React$Component2); function Container() { return _React$Component2.apply(this, arguments) || this; } var _proto2 = Container.prototype; _proto2.render = function render() { var _this5 = this; var context = this.props.context; if (typeof context !== "undefined") { return React.createElement(Consumer, null, function (_ref) { var state = _ref.state, setContextState = _ref.setContextState, mountContainer = _ref.mountContainer; return React.createElement(InnerContainer, _extends({}, _this5.props, { state: state[context], setContextState: setContextState, mountContainer: mountContainer })); }); } return React.createElement(InnerContainer, this.props); }; return Container; }(React.Component); var reduxDevtoolsExtension = typeof window !== "undefined" && window.__REDUX_DEVTOOLS_EXTENSION__; var Provider = /*#__PURE__*/ function (_React$Component) { _inheritsLoose(Provider, _React$Component); function Provider(props) { var _this; _this = _React$Component.call(this, props) || this; _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "containers", {}); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "devtools", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "mountContainer", function (context, onMount) { if (!_this.containers[context]) { _this.containers[context] = 0; if (onMount) _this.setState(null, onMount); } _this.containers[context] += 1; return function (onUnmount) { if (_this.containers[context] === 1 && onUnmount) onUnmount(); _this.containers[context] -= 1; }; }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "setContextState", function (context, updater, callback, type) { var prevState; var updaterFn = function updaterFn(state) { var _Object$assign; prevState = state.state; return { state: Object.assign({}, state.state, (_Object$assign = {}, _Object$assign[context] = Object.assign({}, state.state[context], parseUpdater(updater, state.state[context] || {})), _Object$assign)) }; }; var callbackFn = function callbackFn() { if (_this.props.onUpdate) { var onUpdateProps = _objectSpread({}, _this.getProps("Provider/onUpdate"), { prevState: prevState, context: context, type: type }); _this.props.onUpdate(onUpdateProps); } if (callback) callback(); // istanbul ignore next if (_this.devtools && type) { var devtoolsType = context ? context + "/" + type : type; _this.devtools.send(devtoolsType, _this.state.state); } }; // @ts-ignore _this.setState(updaterFn, callbackFn); }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getProps", function (type) { var _this$state = _this.state, state = _this$state.state, setContextState = _this$state.setContextState; return { state: state, setContextState: function (_setContextState) { function setContextState(_x, _x2, _x3) { return _setContextState.apply(this, arguments); } setContextState.toString = function () { return _setContextState.toString(); }; return setContextState; }(function (context, updater, callback) { return setContextState(context, updater, callback, type); }) }; }); var devtools = props.devtools, initialState = props.initialState; _this.state = { state: initialState, mountContainer: _this.mountContainer, setContextState: _this.setContextState }; // istanbul ignore next if (devtools && reduxDevtoolsExtension) { _this.devtools = reduxDevtoolsExtension.connect({ name: "Context" }); _this.devtools.init(initialState); _this.devtools.subscribe(function (message) { if (message.type === "DISPATCH" && message.state) { _this.setState(function (state) { return { state: Object.assign({}, state.state, JSON.parse(message.state)) }; }); } }); } return _this; } var _proto = Provider.prototype; _proto.componentDidMount = function componentDidMount() { if (this.props.onMount) { this.props.onMount(this.getProps("Provider/onMount")); } }; _proto.componentWillUnmount = function componentWillUnmount() { if (this.props.onUnmount) { var _this$getProps = this.getProps(), _setContextState2 = _this$getProps.setContextState, args = _objectWithoutPropertiesLoose(_this$getProps, ["setContextState"]); this.props.onUnmount(args); } // istanbul ignore next if (this.devtools && reduxDevtoolsExtension) { this.devtools.unsubscribe(); reduxDevtoolsExtension.disconnect(); } }; _proto.render = function render() { return (// @ts-ignore React.createElement(Context.Provider, { value: this.state }, this.props.children) ); }; return Provider; }(React.Component); _defineProperty(Provider, "defaultProps", { initialState: {} }); exports.Consumer = Consumer; exports.Container = Container; exports.Provider = Provider;