mobx-react-lite
Version:
Lightweight React bindings for MobX based on React 16.8+ and Hooks
126 lines • 5.26 kB
JavaScript
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
import { Reaction } from "mobx";
import React from "react";
import { printDebugValue } from "./utils/printDebugValue";
import { addReactionToTrack, recordReactionAsCommitted } from "./utils/reactionCleanupTracking";
import { isUsingStaticRendering } from "./staticRendering";
function observerComponentNameFor(baseComponentName) {
return "observer".concat(baseComponentName);
}
/**
* We use class to make it easier to detect in heap snapshots by name
*/
var ObjectToBeRetainedByReact = /** @class */ (function () {
function ObjectToBeRetainedByReact() {
}
return ObjectToBeRetainedByReact;
}());
function objectToBeRetainedByReactFactory() {
return new ObjectToBeRetainedByReact();
}
export function useObserver(fn, baseComponentName) {
if (baseComponentName === void 0) { baseComponentName = "observed"; }
if (isUsingStaticRendering()) {
return fn();
}
var _a = __read(React.useState(objectToBeRetainedByReactFactory), 1), objectRetainedByReact = _a[0];
// Force update, see #2982
var _b = __read(React.useState(), 2), setState = _b[1];
var forceUpdate = function () { 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.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 = new Reaction(observerComponentNameFor(baseComponentName), 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_1.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_1.changedBeforeMount = true;
}
});
var trackingData_1 = addReactionToTrack(reactionTrackingRef, newReaction, objectRetainedByReact);
}
var reaction = reactionTrackingRef.current.reaction;
React.useDebugValue(reaction, printDebugValue);
React.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: new Reaction(observerComponentNameFor(baseComponentName), 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;
}
//# sourceMappingURL=useObserver.js.map