UNPKG

@tacky/store

Version:

State management framework based on react

210 lines (186 loc) 6.99 kB
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; import _createClass from "@babel/runtime/helpers/esm/createClass"; import { CURRENT_MATERIAL_TYPE, NAMESPACE } from '../const/symbol'; import { EMaterialType } from '../interfaces'; import { isPlainObject, convert2UniqueString, hasOwn, isObject, bind, isDomain } from '../utils/common'; import { invariant } from '../utils/error'; import generateUUID from '../utils/uuid'; import { depCollector, historyCollector } from './collector'; import { canObserve } from '../utils/decorator'; import { store } from './store'; var proxyCache = new WeakMap(); var rawCache = new WeakMap(); var rootKeyCache = new WeakMap(); export var materialCallStack = []; /** * Framework base class 'Domain', class must be extends this base class which is need to be observable. */ export var Domain = /*#__PURE__*/function () { function Domain() { _classCallCheck(this, Domain); // prompt: add property do not forget sync to black list this.properties = {}; this.reactorConfigMap = {}; var target = Object.getPrototypeOf(this); var domainName = target.constructor.name || 'TACKY_DOMAIN'; var namespace = "".concat(domainName, "_").concat(generateUUID()); this[CURRENT_MATERIAL_TYPE] = EMaterialType.DEFAULT; this[NAMESPACE] = namespace; } _createClass(Domain, [{ key: "propertyGet", value: function propertyGet(key, config) { var stringKey = convert2UniqueString(key); var v = this.properties[stringKey]; this.reactorConfigMap[stringKey] = config; depCollector.collect(this, stringKey); return isObject(v) && !isDomain(v) && config.deepProxy ? this.proxyReactive(v, stringKey) : v; } }, { key: "propertySet", value: function propertySet(key, v, config) { var stringKey = convert2UniqueString(key); this.illegalAssignmentCheck(this, stringKey); var oldValue = this.properties[stringKey]; this.reactorConfigMap[stringKey] = config; if (oldValue !== v) { this.properties[stringKey] = v; historyCollector.collect(this, stringKey, { type: "set" /* SET */ , beforeUpdate: oldValue, didUpdate: v }, config.isNeedRecord); } } }, { key: "proxySet", value: function proxySet(target, key, value, receiver) { var stringKey = convert2UniqueString(key); this.illegalAssignmentCheck(target, stringKey); var hadKey = hasOwn(target, key); var oldValue = target[key]; var rootKey = rootKeyCache.get(target); // do nothing if target is in the prototype chain if (target === proxyCache.get(receiver)) { var result = Reflect.set(target, key, value, receiver); if (!hadKey) { historyCollector.collect(target, stringKey, { type: "add" /* ADD */ , beforeUpdate: oldValue, didUpdate: value }, this.reactorConfigMap[rootKey].isNeedRecord); } else if (value !== oldValue) { historyCollector.collect(target, stringKey, { type: "set" /* SET */ , beforeUpdate: oldValue, didUpdate: value }, this.reactorConfigMap[rootKey].isNeedRecord); } return result; } return false; } }, { key: "proxyGet", value: function proxyGet(target, key, receiver) { var res = Reflect.get(target, key, receiver); var stringKey = convert2UniqueString(key); var rootKey = rootKeyCache.get(target); depCollector.collect(target, stringKey); return isObject(res) && !isDomain(res) ? this.proxyReactive(res, rootKey) : res; } }, { key: "proxyOwnKeys", value: function proxyOwnKeys(target) { depCollector.collect(target, "iterate" /* ITERATE */ ); return Reflect.ownKeys(target); } /** * proxy value could be boolean, string, number, undefined, null, custom instance, array[], plainObject{} * @todo: support Map、Set、WeakMap、WeakSet */ }, { key: "proxyReactive", value: function proxyReactive(raw, rootKey) { var _this = this; rootKeyCache.set(raw, rootKey); // different props use same ref var refProxy = rawCache.get(raw); if (refProxy !== void 0) { return refProxy; } // raw is already a Proxy if (proxyCache.has(raw)) { return raw; } if (!canObserve(raw)) { return raw; } var proxy = new Proxy(raw, { get: bind(_this.proxyGet, _this), set: bind(_this.proxySet, _this), ownKeys: bind(_this.proxyOwnKeys, _this) }); proxyCache.set(proxy, raw); rawCache.set(raw, proxy); return proxy; } /** * the syntax sweet of updating state out of mutation */ }, { key: "$update", value: function $update(obj, actionName) { invariant(isPlainObject(obj), 'resetState(...) param type error. Param should be a plain object.'); this.dispatch(obj, actionName); } /** * observed value could be assigned value to @reactor only in @mutation/$update, otherwise throw error. */ }, { key: "illegalAssignmentCheck", value: function illegalAssignmentCheck(target, stringKey) { if (depCollector.isObserved(target, stringKey)) { var length = materialCallStack.length; var firstLevelMaterial = materialCallStack[length - 1] || EMaterialType.DEFAULT; invariant(firstLevelMaterial === EMaterialType.MUTATION || firstLevelMaterial === EMaterialType.UPDATE || firstLevelMaterial === EMaterialType.TIME_TRAVEL, 'You cannot update value to observed \'@reactor property\' directly. Please use mutation or $update({}).'); } } }, { key: "dispatch", value: function dispatch(obj, actionName) { var original = function original() { var keys = Object.keys(obj); for (var i = 0, len = keys.length; i < len; i++) { var key = keys[i]; this[key] = obj[key]; } }; this[CURRENT_MATERIAL_TYPE] = EMaterialType.UPDATE; materialCallStack.push(this[CURRENT_MATERIAL_TYPE]); // update state before store init if (store === void 0) { original.call(this); materialCallStack.pop(); var _length = materialCallStack.length; this[CURRENT_MATERIAL_TYPE] = materialCallStack[_length - 1] || EMaterialType.DEFAULT; return; } // update state after store init store.dispatch({ name: actionName || "$update_".concat(generateUUID()), payload: [], type: EMaterialType.UPDATE, domain: this, original: bind(original, this) }); materialCallStack.pop(); var length = materialCallStack.length; this[CURRENT_MATERIAL_TYPE] = materialCallStack[length - 1] || EMaterialType.DEFAULT; } }]); return Domain; }();