@tixel/vuex-correlated-effects
Version:
Correlated effects is a side effect model for Vuex. Correlated effects use subscribers to provide new sources of actions such as network requests, web socket messages and time-based events. Effects can be correlated back to the component that initially di
229 lines (186 loc) • 9.66 kB
JavaScript
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
import _every from 'lodash-es/every.js';
import _some from 'lodash-es/some.js';
var VuexEffects = function VuexEffects(store) {
var effectsList = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
return {
install: function install(VueGlobal) {
function matchComponentProps(path, action) {
var _this = this;
var effectMatchers = path[action.type].matchComponentProps;
if (effectMatchers && effectMatchers.length > 0 && !_every(effectMatchers, function (propertyToMatch) {
var _action$payload;
if (!(action !== null && action !== void 0 && (_action$payload = action.payload) !== null && _action$payload !== void 0 && _action$payload.match)) {
console.error('[vuex-effects] matchComponentProps is set and expects the action sends a payload with match');
return false;
}
if (_typeof(_this === null || _this === void 0 ? void 0 : _this[propertyToMatch]) === undefined) {
console.error("[vuex-effects] matchComponentProps is set and expects the component to have props \"".concat(effectMatchers, "\". \"").concat(propertyToMatch, "\", doesn't exist, you need to set this in the component props"));
return false;
}
return _some(action.payload.match, function (match) {
if (!(match !== null && match !== void 0 && match[propertyToMatch])) {
console.error("[vuex-effects] matchComponentProps is set and expects the action to send, \"".concat(propertyToMatch, "\" as a property in the match array, this action is sending \"").concat(Object.keys(match), "\""));
return false;
}
return match[propertyToMatch] === _this[propertyToMatch];
});
})) {
// do not execute the action as it needs to match all properties
return true;
}
}
function callActionEffect(effectsPath, stage, action, state) {
var prepend = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
var actionsPath = effectsPath.actions; // matchComponentProps will match the component properties from the component
// and the action
if (matchComponentProps.apply(this, [actionsPath, action])) {
return;
} // exit if effect's prepend not the same as subscriber
if (_typeof(actionsPath[action.type]) === 'object') {
if (!!actionsPath[action.type].prepend !== prepend) {
return;
}
} else if (typeof actionsPath[action.type] === 'function' && prepend) {
return;
}
if (stage === 'before') {
// if effect is function
if (typeof actionsPath[action.type] === 'function') {
actionsPath[action.type].apply(this, [action, state]);
return;
} // if effect is object and it has handler function
if (_typeof(actionsPath[action.type]) === 'object' && typeof actionsPath[action.type].handler === 'function') {
actionsPath[action.type].handler.apply(this, [action, state]);
return;
} // if effect is object with before function
if (_typeof(actionsPath[action.type]) === 'object' && typeof actionsPath[action.type][stage] === 'function') {
actionsPath[action.type][stage].apply(this, [action, state]);
}
} else if (stage === 'after') {
// if effect is object with after function
if (_typeof(actionsPath[action.type]) === 'object' && typeof actionsPath[action.type][stage] === 'function') {
actionsPath[action.type][stage].apply(this, [action, state]);
}
}
}
function callMutationEffect(effectsPath, mutation, state) {
var prepend = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var mutationsPath = effectsPath.mutations; // exit if effect's prepend not the same as subscriber
if (_typeof(mutationsPath[mutation.type]) === 'object') {
if (!!mutationsPath[mutation.type].prepend !== prepend) {
return;
}
} else if (typeof mutationsPath[mutation.type] === 'function' && prepend) {
return;
} // if effect is function
if (typeof mutationsPath[mutation.type] === 'function') {
mutationsPath[mutation.type].apply(this, [mutation, state]);
return;
} // if effect is object and it has handler function
if (_typeof(mutationsPath[mutation.type]) === 'object' && typeof mutationsPath[mutation.type].handler === 'function') {
mutationsPath[mutation.type].handler.apply(this, [mutation, state]);
}
} // action wrapper fn
function actionFn(effectsPath, effectActionsList) {
var _this2 = this;
var prepend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
return {
before: function before(action, state) {
if (effectActionsList.includes(action.type)) {
callActionEffect.apply(_this2, [effectsPath, 'before', action, state, prepend]);
}
},
after: function after(action, state) {
if (effectActionsList.includes(action.type)) {
callActionEffect.apply(_this2, [effectsPath, 'after', action, state, prepend]);
}
}
};
} // mutation wrapper fn
function mutationFn(effectsPath, effectActionsList) {
var _this3 = this;
var prepend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
return function (mutation, state) {
if (effectActionsList.includes(mutation.type)) {
callMutationEffect.apply(_this3, [effectsPath, mutation, state, prepend]);
}
};
} // register effects for component
VueGlobal.mixin({
beforeUnmount: function beforeUnmount() {
if (Array.isArray(this.subscribers)) {
this.subscribers.forEach(function (subscriber) {
return subscriber();
});
}
},
beforeCreate: function beforeCreate() {
var _this4 = this;
var effects = this.$options.effects;
if (effects) {
this.subscribers = [];
var effectTypes = Object.keys(effects);
effectTypes.forEach(function (effectType) {
var effectActionsList = Object.keys(effects[effectType]); // subscribe to two identical events, with 'prepend' option and without it
// so we have only two subscriber for all events
// for actions and mutations
switch (effectType) {
case 'actions':
{
_this4.subscribers.push(store.subscribeAction(actionFn.apply(_this4, [_this4.$options.effects, effectActionsList])), store.subscribeAction(actionFn.apply(_this4, [_this4.$options.effects, effectActionsList, true]), {
prepend: true
}));
break;
}
case 'mutations':
{
_this4.subscribers.push(store.subscribe(mutationFn.apply(_this4, [_this4.$options.effects, effectActionsList])), store.subscribe(mutationFn.apply(_this4, [_this4.$options.effects, effectActionsList, true]), {
prepend: true
}));
break;
}
default:
{
throw new Error("[vuex-effects] Unrecognized effect section ".concat(effectType, " \n Maybe you mean 'actions' or 'mutations'?"));
}
}
});
}
}
}); // register global effects
effectsList.forEach(function (effectsItem) {
var effects = effectsItem.effects;
var effectTypes = Object.keys(effects);
effectTypes.forEach(function (effectType) {
var effectActionsList = Object.keys(effects[effectType]); // subscribe to two identical events, with 'prepend' option and without it
// so we have only two subscriber for all events
// for actions and mutations
switch (effectType) {
case 'actions':
{
store.subscribeAction(actionFn.apply(effectsItem, [effectsItem.effects, effectActionsList]));
store.subscribeAction(actionFn.apply(effectsItem, [effectsItem.effects, effectActionsList, true]), {
prepend: true
});
break;
}
case 'mutations':
{
store.subscribe(mutationFn.apply(effectsItem, [effectsItem.effects, effectActionsList]));
store.subscribe(mutationFn.apply(effectsItem, [effectsItem.effects, effectActionsList, true]), {
prepend: true
});
break;
}
default:
{
throw new Error("[vuex-effects] Unrecognized effect section ".concat(effectType));
}
}
});
});
}
};
};
export default VuexEffects;