UNPKG

lobx-react

Version:

Lightweight React bindings for lobx based on React 16.8+ and Hooks

922 lines (751 loc) 33.6 kB
(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