lobx-react
Version:
Lightweight React bindings for lobx based on React 16.8+ and Hooks
922 lines (751 loc) • 33.6 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('lobx'), require('react-dom')) :
typeof define === 'function' && define.amd ? define(['exports', 'react', 'lobx', 'react-dom'], factory) :
(global = global || self, factory(global.lobxreact = {}, global.React, global.lobx, global.ReactDOM));
}(this, (function (exports, React, lobx, reactDom) { 'use strict';
var React__default = 'default' in React ? React['default'] : React;
if (!React.useState) {
throw new Error("lobx-react requires React with Hooks support");
}
var globalIsUsingStaticRendering = false;
function enableStaticRendering(enable) {
globalIsUsingStaticRendering = enable;
}
function isUsingStaticRendering() {
return globalIsUsingStaticRendering;
}
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 _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (it) return (it = it.call(o)).next.bind(it);
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var FinalizationRegistryLocal = typeof FinalizationRegistry === "undefined" ? undefined : FinalizationRegistry;
function createTrackingData(reaction) {
var trackingData = {
reaction: reaction,
mounted: false,
changedBeforeMount: false,
cleanAt: Date.now() + CLEANUP_LEAKED_REACTIONS_AFTER_MILLIS
};
return trackingData;
}
/**
* The minimum time before we'll clean up a Reaction created in a render
* for a component that hasn't managed to run its effects. This needs to
* be big enough to ensure that a component won't turn up and have its
* effects run without being re-rendered.
*/
var CLEANUP_LEAKED_REACTIONS_AFTER_MILLIS = 10000;
/**
* The frequency with which we'll check for leaked reactions.
*/
var CLEANUP_TIMER_LOOP_MILLIS = 10000;
/**
* FinalizationRegistry-based uncommitted reaction cleanup
*/
function createReactionCleanupTrackingUsingFinalizationRegister(FinalizationRegistry) {
var cleanupTokenToReactionTrackingMap = new Map();
var globalCleanupTokensCounter = 1;
var registry = new FinalizationRegistry(function cleanupFunction(token) {
var trackedReaction = cleanupTokenToReactionTrackingMap.get(token);
if (trackedReaction) {
trackedReaction.reaction.dispose();
cleanupTokenToReactionTrackingMap.delete(token);
}
});
return {
addReactionToTrack: function addReactionToTrack(reactionTrackingRef, reaction, objectRetainedByReact) {
var token = globalCleanupTokensCounter++;
registry.register(objectRetainedByReact, token, reactionTrackingRef);
reactionTrackingRef.current = createTrackingData(reaction);
reactionTrackingRef.current.finalizationRegistryCleanupToken = token;
cleanupTokenToReactionTrackingMap.set(token, reactionTrackingRef.current);
return reactionTrackingRef.current;
},
recordReactionAsCommitted: function recordReactionAsCommitted(reactionRef) {
registry.unregister(reactionRef);
if (reactionRef.current && reactionRef.current.finalizationRegistryCleanupToken) {
cleanupTokenToReactionTrackingMap.delete(reactionRef.current.finalizationRegistryCleanupToken);
}
},
forceCleanupTimerToRunNowForTests: function forceCleanupTimerToRunNowForTests() {// When FinalizationRegistry in use, this this is no-op
},
resetCleanupScheduleForTests: function resetCleanupScheduleForTests() {// When FinalizationRegistry in use, this this is no-op
}
};
}
/**
* timers, gc-style, uncommitted reaction cleanup
*/
function createTimerBasedReactionCleanupTracking() {
/**
* Reactions created by components that have yet to be fully mounted.
*/
var uncommittedReactionRefs = new Set();
/**
* Latest 'uncommitted reactions' cleanup timer handle.
*/
var reactionCleanupHandle;
/* istanbul ignore next */
/**
* Only to be used by test functions; do not export outside of lobx-react
*/
function forceCleanupTimerToRunNowForTests() {
// This allows us to control the execution of the cleanup timer
// to force it to run at awkward times in unit tests.
if (reactionCleanupHandle) {
clearTimeout(reactionCleanupHandle);
cleanUncommittedReactions();
}
}
/* istanbul ignore next */
function resetCleanupScheduleForTests() {
if (uncommittedReactionRefs.size > 0) {
for (var _iterator = _createForOfIteratorHelperLoose(uncommittedReactionRefs), _step; !(_step = _iterator()).done;) {
var ref = _step.value;
var tracking = ref.current;
if (tracking) {
tracking.reaction.dispose();
ref.current = null;
}
}
uncommittedReactionRefs.clear();
}
if (reactionCleanupHandle) {
clearTimeout(reactionCleanupHandle);
reactionCleanupHandle = undefined;
}
}
function ensureCleanupTimerRunning() {
if (reactionCleanupHandle === undefined) {
reactionCleanupHandle = setTimeout(cleanUncommittedReactions, CLEANUP_TIMER_LOOP_MILLIS);
}
}
function scheduleCleanupOfReactionIfLeaked(ref) {
uncommittedReactionRefs.add(ref);
ensureCleanupTimerRunning();
}
function recordReactionAsCommitted(reactionRef) {
uncommittedReactionRefs.delete(reactionRef);
}
/**
* Run by the cleanup timer to dispose any outstanding reactions
*/
function cleanUncommittedReactions() {
reactionCleanupHandle = undefined; // Loop through all the candidate leaked reactions; those older
// than CLEANUP_LEAKED_REACTIONS_AFTER_MILLIS get tidied.
var now = Date.now();
uncommittedReactionRefs.forEach(function (ref) {
var tracking = ref.current;
if (tracking) {
if (now >= tracking.cleanAt) {
// It's time to tidy up this leaked reaction.
tracking.reaction.dispose();
ref.current = null;
uncommittedReactionRefs.delete(ref);
}
}
});
if (uncommittedReactionRefs.size > 0) {
// We've just finished a round of cleanups but there are still
// some leak candidates outstanding.
ensureCleanupTimerRunning();
}
}
return {
addReactionToTrack: function addReactionToTrack(reactionTrackingRef, reaction,
/**
* On timer based implementation we don't really need this object,
* but we keep the same api
*/
objectRetainedByReact) {
reactionTrackingRef.current = createTrackingData(reaction);
scheduleCleanupOfReactionIfLeaked(reactionTrackingRef);
return reactionTrackingRef.current;
},
recordReactionAsCommitted: recordReactionAsCommitted,
forceCleanupTimerToRunNowForTests: forceCleanupTimerToRunNowForTests,
resetCleanupScheduleForTests: resetCleanupScheduleForTests
};
}
var _ref = FinalizationRegistryLocal ? /*#__PURE__*/createReactionCleanupTrackingUsingFinalizationRegister(FinalizationRegistryLocal) : /*#__PURE__*/createTimerBasedReactionCleanupTracking(),
addReactionToTrack = _ref.addReactionToTrack,
recordReactionAsCommitted = _ref.recordReactionAsCommitted,
resetCleanupScheduleForTests = _ref.resetCleanupScheduleForTests;
var EMPTY_OBJECT = {};
var schedulerMap = /*#__PURE__*/new WeakMap();
function getScheduler(graph) {
var scheduler = schedulerMap.get(graph);
if (!scheduler) {
scheduler = lobx.createScheduler(function (fn) {
return reactDom.unstable_batchedUpdates(fn);
}, {
graph: graph
});
schedulerMap.set(graph, scheduler);
}
return scheduler;
}
/**
* We use class to make it easier to detect in heap snapshots by name
*/
var ObjectToBeRetainedByReact = function ObjectToBeRetainedByReact() {};
function objectToBeRetainedByReactFactory() {
return new ObjectToBeRetainedByReact();
}
function useObserver(fn, options) {
if (options === void 0) {
options = EMPTY_OBJECT;
}
if (isUsingStaticRendering()) {
return fn();
}
var graph = options.graph || lobx.getDefaultGraph();
var scheduler = getScheduler(graph);
var _React$useState = React__default.useState(objectToBeRetainedByReactFactory),
objectRetainedByReact = _React$useState[0]; // Force update, see #2982
var _React$useState2 = React__default.useState(),
setState = _React$useState2[1];
var forceUpdate = function forceUpdate() {
return setState([]);
}; // StrictMode/ConcurrentMode/Suspense may mean that our component is
// rendered and abandoned multiple times, so we need to track leaked
// Reactions.
var reactionTrackingRef = React__default.useRef(null);
if (!reactionTrackingRef.current) {
// First render for this component (or first time since a previous
// reaction from an abandoned render was disposed).
var newReaction = scheduler.listener(function () {
// Observable has changed, meaning we want to re-render
// BUT if we're a component that hasn't yet got to the useEffect()
// stage, we might be a component that _started_ to render, but
// got dropped, and we don't want to make state changes then.
// (It triggers warnings in StrictMode, for a start.)
if (trackingData.mounted) {
// We have reached useEffect(), so we're mounted, and can trigger an update
forceUpdate();
} else {
// We haven't yet reached useEffect(), so we'll need to trigger a re-render
// when (and if) useEffect() arrives.
trackingData.changedBeforeMount = true;
}
});
var trackingData = addReactionToTrack(reactionTrackingRef, newReaction, objectRetainedByReact);
}
var reaction = reactionTrackingRef.current.reaction;
React__default.useEffect(function () {
// Called on first mount only
recordReactionAsCommitted(reactionTrackingRef);
if (reactionTrackingRef.current) {
// Great. We've already got our reaction from our render;
// all we need to do is to record that it's now mounted,
// to allow future observable changes to trigger re-renders
reactionTrackingRef.current.mounted = true; // Got a change before first mount, force an update
if (reactionTrackingRef.current.changedBeforeMount) {
reactionTrackingRef.current.changedBeforeMount = false;
forceUpdate();
}
} else {
// The reaction we set up in our render has been disposed.
// This can be due to bad timings of renderings, e.g. our
// component was paused for a _very_ long time, and our
// reaction got cleaned up
// Re-create the reaction
reactionTrackingRef.current = {
reaction: scheduler.listener(function () {
// We've definitely already been mounted at this point
forceUpdate();
}),
mounted: true,
changedBeforeMount: false,
cleanAt: Infinity
};
forceUpdate();
}
return function () {
reactionTrackingRef.current.reaction.dispose();
reactionTrackingRef.current = null;
};
}, []); // render the original component, but have the
// reaction track the observables, so that rendering
// can be invalidated (see above) once a dependency changes
var rendering;
var exception;
reaction.track(function () {
try {
rendering = fn();
} catch (e) {
exception = e;
}
});
if (exception) {
throw exception; // re-throw any exceptions caught during rendering
}
return rendering;
}
function observer(baseComponent, options) {
// The working of observer is explained step by step in this talk: https://www.youtube.com/watch?v=cPF4iBedoF0&feature=youtu.be&t=1307
if (isUsingStaticRendering()) {
return baseComponent;
}
var realOptions = _extends({
forwardRef: false
}, options);
var baseComponentName = baseComponent.displayName || baseComponent.name;
var wrappedComponent = function wrappedComponent(props, ref) {
return useObserver(function () {
return baseComponent(props, ref);
}, options && {
graph: options.graph
});
};
wrappedComponent.displayName = baseComponentName; // memo; we are not interested in deep updates
// in props; we assume that if deep objects are changed,
// this is in observables, which would have been tracked anyway
var memoComponent;
if (realOptions.forwardRef) {
// we have to use forwardRef here because:
// 1. it cannot go before memo, only after it
// 2. forwardRef converts the function into an actual component, so we can't let the baseComponent do it
// since it wouldn't be a callable function anymore
memoComponent = React.memo(React.forwardRef(wrappedComponent));
} else {
memoComponent = React.memo(wrappedComponent);
}
copyStaticProperties(baseComponent, memoComponent);
memoComponent.displayName = baseComponentName;
return memoComponent;
} // based on https://github.com/mridgway/hoist-non-react-statics/blob/master/src/index.js
var hoistBlockList = {
$$typeof: true,
render: true,
compare: true,
type: true
};
function copyStaticProperties(base, target) {
Object.keys(base).forEach(function (key) {
if (!hoistBlockList[key]) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(base, key));
}
});
}
function ObserverComponent(_ref) {
var children = _ref.children,
render = _ref.render;
var component = children || render;
if (typeof component !== "function") {
return null;
}
return useObserver(component);
}
{
ObserverComponent.propTypes = {
children: ObserverPropsCheck,
render: ObserverPropsCheck
};
}
ObserverComponent.displayName = "Observer";
function ObserverPropsCheck(props, key, componentName, location, propFullName) {
var extraKey = key === "children" ? "render" : "children";
var hasProp = typeof props[key] === "function";
var hasExtraProp = typeof props[extraKey] === "function";
if (hasProp && hasExtraProp) {
return new Error("Lobx Observer: Do not use children and render in the same time in`" + componentName);
}
if (hasProp || hasExtraProp) {
return null;
}
return new Error("Invalid prop `" + propFullName + "` of type `" + typeof props[key] + "` supplied to" + " `" + componentName + "`, expected `function`.");
}
var symbolId = 0;
function createSymbol(name) {
if (typeof Symbol === "function") {
return Symbol(name);
}
var symbol = "__$lobx-react " + name + " (" + symbolId + ")";
symbolId++;
return symbol;
}
var createdSymbols = {};
function newSymbol(name) {
if (!createdSymbols[name]) {
createdSymbols[name] = createSymbol(name);
}
return createdSymbols[name];
}
function shallowEqual(objA, objB) {
//From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js
if (is(objA, objB)) return true;
if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) {
return false;
}
var keysA = Object.keys(objA);
var keysB = Object.keys(objB);
if (keysA.length !== keysB.length) return false;
for (var i = 0; i < keysA.length; i++) {
if (!Object.hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
return false;
}
}
return true;
}
function is(x, y) {
// From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js
if (x === y) {
return x !== 0 || 1 / x === 1 / y;
} else {
return x !== x && y !== y;
}
} // based on https://github.com/mridgway/hoist-non-react-statics/blob/master/src/index.js
/**
* Helper to set `prop` to `this` as non-enumerable (hidden prop)
* @param target
* @param prop
* @param value
*/
function setHiddenProp(target, prop, value) {
if (!Object.hasOwnProperty.call(target, prop)) {
Object.defineProperty(target, prop, {
enumerable: false,
configurable: true,
writable: true,
value: value
});
} else {
target[prop] = value;
}
}
/**
* Utilities for patching componentWillUnmount, to make sure @disposeOnUnmount works correctly icm with user defined hooks
* and the handler provided by lobx-react
*/
var lobxMixins = /*#__PURE__*/newSymbol("patchMixins");
var lobxPatchedDefinition = /*#__PURE__*/newSymbol("patchedDefinition");
function getMixins(target, methodName) {
var mixins = target[lobxMixins] = target[lobxMixins] || {};
var methodMixins = mixins[methodName] = mixins[methodName] || {};
methodMixins.locks = methodMixins.locks || 0;
methodMixins.methods = methodMixins.methods || [];
return methodMixins;
}
function wrapper(realMethod, mixins) {
var _this = this;
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
args[_key - 2] = arguments[_key];
}
// locks are used to ensure that mixins are invoked only once per invocation, even on recursive calls
mixins.locks++;
try {
var retVal;
if (realMethod !== undefined && realMethod !== null) {
retVal = realMethod.apply(this, args);
}
return retVal;
} finally {
mixins.locks--;
if (mixins.locks === 0) {
mixins.methods.forEach(function (mx) {
mx.apply(_this, args);
});
}
}
}
function wrapFunction(realMethod, mixins) {
var fn = function fn() {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
wrapper.call.apply(wrapper, [this, realMethod, mixins].concat(args));
};
return fn;
}
function patch(target, methodName, mixinMethod) {
var mixins = getMixins(target, methodName);
if (mixins.methods.indexOf(mixinMethod) < 0) {
mixins.methods.push(mixinMethod);
}
var oldDefinition = Object.getOwnPropertyDescriptor(target, methodName);
if (oldDefinition && oldDefinition[lobxPatchedDefinition]) {
// already patched definition, do not repatch
return;
}
var originalMethod = target[methodName];
var newDefinition = createDefinition(target, methodName, oldDefinition ? oldDefinition.enumerable : undefined, mixins, originalMethod);
Object.defineProperty(target, methodName, newDefinition);
}
function createDefinition(target, methodName, enumerable, mixins, originalMethod) {
var _ref;
var wrappedFunc = wrapFunction(originalMethod, mixins);
return _ref = {}, _ref[lobxPatchedDefinition] = true, _ref.get = function get() {
return wrappedFunc;
}, _ref.set = function set(value) {
if (this === target) {
wrappedFunc = wrapFunction(value, mixins);
} else {
// when it is an instance of the prototype/a child prototype patch that particular case again separately
// since we need to store separate values depending on wether it is the actual instance, the prototype, etc
// e.g. the method for super might not be the same as the method for the prototype which might be not the same
// as the method for the instance
var newDefinition = createDefinition(this, methodName, enumerable, mixins, value);
Object.defineProperty(this, methodName, newDefinition);
}
}, _ref.configurable = true, _ref.enumerable = enumerable, _ref;
}
var lobxAdminProperty = "$lobx";
var lobxObserverProperty = /*#__PURE__*/newSymbol("islobxReactObserver");
var lobxIsUnmounted = /*#__PURE__*/newSymbol("isUnmounted");
var skipRenderKey = /*#__PURE__*/newSymbol("skipRender");
var isForcingUpdateKey = /*#__PURE__*/newSymbol("isForcingUpdate");
function makeClassComponentObserver(componentClass) {
var target = componentClass.prototype;
if (componentClass[lobxObserverProperty]) {
var displayName = getDisplayName(target);
console.warn("The provided component class (" + displayName + ") \n has already been declared as an observer component.");
} else {
componentClass[lobxObserverProperty] = true;
}
if (target.componentWillReact) throw new Error("The componentWillReact life-cycle event is no longer supported");
if (componentClass["__proto__"] !== React.PureComponent) {
if (!target.shouldComponentUpdate) target.shouldComponentUpdate = observerSCU;else if (target.shouldComponentUpdate !== observerSCU) // n.b. unequal check, instead of existence check, as @observer might be on superclass as well
throw new Error("It is not allowed to use shouldComponentUpdate in observer based components.");
} // this.props and this.state are made observable, just to make sure @computed fields that
// are defined inside the component, and which rely on state or props, re-compute if state or props change
// (otherwise the computed wouldn't update and become stale on props change, since props are not observable)
// However, this solution is not without it's own problems: https://github.com/lobxjs/lobx-react/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Aobservable-props-or-not+
makeObservableProp(target, "props");
makeObservableProp(target, "state");
var baseRender = target.render;
if (typeof baseRender !== "function") {
var _displayName = getDisplayName(target);
throw new Error("[lobx-react] class component (" + _displayName + ") is missing `render` method." + "\n`observer` requires `render` being a function defined on prototype." + "\n`render = () => {}` or `render = function() {}` is not supported.");
}
target.render = function () {
return makeComponentReactive.call(this, baseRender);
};
patch(target, "componentWillUnmount", function () {
var _this$render$lobxAdmi;
if (isUsingStaticRendering() === true) return;
(_this$render$lobxAdmi = this.render[lobxAdminProperty]) == null ? void 0 : _this$render$lobxAdmi.dispose();
this[lobxIsUnmounted] = true;
if (!this.render[lobxAdminProperty]) {
// Render may have been hot-swapped and/or overriden by a subclass.
var _displayName2 = getDisplayName(this);
console.warn("The reactive render of an observer class component (" + _displayName2 + ") \n was overriden after lobx attached. This may result in a memory leak if the \n overriden reactive render was not properly disposed.");
}
});
return componentClass;
} // Generates a friendly name for debugging
function getDisplayName(comp) {
return comp.displayName || comp.name || comp.constructor && (comp.constructor.displayName || comp.constructor.name) || "<component>";
}
function makeComponentReactive(render) {
var _this = this;
if (isUsingStaticRendering() === true) return render.call(this);
/**
* If props are shallowly modified, react will render anyway,
* so atom.reportChanged() should not result in yet another re-render
*/
setHiddenProp(this, skipRenderKey, false);
/**
* forceUpdate will re-assign this.props. We don't want that to cause a loop,
* so detect these changes
*/
setHiddenProp(this, isForcingUpdateKey, false);
var baseRender = render.bind(this);
var isRenderingPending = false;
var reaction = lobx.listener(function () {
if (!isRenderingPending) {
// N.B. Getting here *before mounting* means that a component constructor has side effects (see the relevant test in misc.js)
// This unidiomatic React usage but React will correctly warn about this so we continue as usual
// See #85 / Pull #44
isRenderingPending = true;
if (_this[lobxIsUnmounted] !== true) {
var hasError = true;
try {
setHiddenProp(_this, isForcingUpdateKey, true);
if (!_this[skipRenderKey]) React.Component.prototype.forceUpdate.call(_this);
hasError = false;
} finally {
setHiddenProp(_this, isForcingUpdateKey, false);
if (hasError) reaction.dispose();
}
}
}
});
reaction["reactComponent"] = this;
reactiveRender[lobxAdminProperty] = reaction;
this.render = reactiveRender;
function reactiveRender() {
isRenderingPending = false;
var exception = undefined;
var rendering = undefined;
reaction.track(function () {
try {
rendering = baseRender();
} catch (e) {
exception = e;
}
});
if (exception) {
throw exception;
}
return rendering;
}
return reactiveRender.call(this);
}
function observerSCU(nextProps, nextState) {
if (isUsingStaticRendering()) {
console.warn("[lobx-react] It seems that a re-rendering of a React component is triggered while in static (server-side) mode. Please make sure components are rendered only once server-side.");
} // update on any state changes (as is the default)
if (this.state !== nextState) {
return true;
} // update if props are shallowly not equal, inspired by PureRenderMixin
// we could return just 'false' here, and avoid the `skipRender` checks etc
// however, it is nicer if lifecycle events are triggered like usually,
// so we return true here if props are shallowly modified.
return !shallowEqual(this.props, nextProps);
}
function makeObservableProp(target, propName) {
var valueHolderKey = newSymbol("reactProp_" + propName + "_valueHolder");
var atomHolderKey = newSymbol("reactProp_" + propName + "_atomHolder");
function getAtom() {
if (!this[atomHolderKey]) {
setHiddenProp(this, atomHolderKey, lobx.atom());
}
return this[atomHolderKey];
}
Object.defineProperty(target, propName, {
configurable: true,
enumerable: true,
get: function get() {
getAtom.call(this).reportObserved();
return this[valueHolderKey];
},
set: function set(v) {
if (!this[isForcingUpdateKey] && !shallowEqual(this[valueHolderKey], v)) {
setHiddenProp(this, valueHolderKey, v);
setHiddenProp(this, skipRenderKey, true);
getAtom.call(this).reportChanged();
setHiddenProp(this, skipRenderKey, false);
} else {
setHiddenProp(this, valueHolderKey, v);
}
}
});
}
var ReactForwardRefSymbol = /*#__PURE__*/Symbol.for("react.forward_ref");
var ReactMemoSymbol = /*#__PURE__*/Symbol.for("react.memo");
/**
* Observer function / decorator
*/
function observer$1(component, opts) {
var anyComp = component;
if (anyComp["islobxInjector"] === true) {
console.warn("lobx observer: You are trying to use 'observer' on a component that already has 'inject'. Please apply 'observer' before applying 'inject'");
}
if (ReactMemoSymbol && anyComp["$$typeof"] === ReactMemoSymbol) {
throw new Error("lobx observer: You are trying to use 'observer' on a function component wrapped in either another observer or 'React.memo'. The observer already applies 'React.memo' for you.");
} // Unwrap forward refs into `<Observer>` component
// we need to unwrap the render, because it is the inner render that needs to be tracked,
// not the ForwardRef HoC
if (ReactForwardRefSymbol && anyComp["$$typeof"] === ReactForwardRefSymbol) {
var baseRender = anyComp["render"];
if (typeof baseRender !== "function") throw new Error("render property of ForwardRef was not a function");
return React.forwardRef(function ObserverForwardRef() {
var args = arguments;
return React.createElement(ObserverComponent, null, function () {
return baseRender.apply(undefined, args);
});
});
} // Function component
if (typeof component === "function" && (!component.prototype || !component.prototype.render) && !anyComp["isReactClass"] && !Object.prototype.isPrototypeOf.call(React.Component, component)) {
return observer(component, opts);
}
return makeClassComponentObserver(component);
}
function defaultConfigure(key, proxy) {
var descriptor = Object.getOwnPropertyDescriptor(proxy, key);
if (descriptor && typeof descriptor.value === "function") {
return lobx.action.opts({
bound: true,
untracked: true
});
}
return undefined;
}
function isPlainObject(value) {
if (value === null || typeof value !== "object") return false;
var proto = Object.getPrototypeOf(value);
return proto === Object.prototype || proto === null;
}
function useObservable(initializer, annotations) {
return React.useState(function () {
var obj = typeof initializer === "function" ? initializer() : initializer;
if (!isPlainObject(obj)) {
return lobx.observable(obj);
}
return lobx.observable.configure(annotations ? function (key, proxy) {
var result;
if (annotations) {
if (Object.prototype.hasOwnProperty.call(annotations, key)) {
result = annotations[key];
}
}
if (!result) {
return defaultConfigure(key, proxy);
}
return result;
} : defaultConfigure, typeof initializer === "function" ? initializer() : initializer, {
withDefaults: true
});
})[0];
}
exports.Observer = ObserverComponent;
exports.clearTimers = resetCleanupScheduleForTests;
exports.enableStaticRendering = enableStaticRendering;
exports.isUsingStaticRendering = isUsingStaticRendering;
exports.observer = observer$1;
exports.useObservable = useObservable;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=lobxreact.umd.development.js.map