UNPKG

5.26 kBJavaScriptView Raw
1var __read = (this && this.__read) || function (o, n) {
2 var m = typeof Symbol === "function" && o[Symbol.iterator];
3 if (!m) return o;
4 var i = m.call(o), r, ar = [], e;
5 try {
6 while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
7 }
8 catch (error) { e = { error: error }; }
9 finally {
10 try {
11 if (r && !r.done && (m = i["return"])) m.call(i);
12 }
13 finally { if (e) throw e.error; }
14 }
15 return ar;
16};
17import { Reaction } from "mobx";
18import React from "react";
19import { printDebugValue } from "./utils/printDebugValue";
20import { addReactionToTrack, recordReactionAsCommitted } from "./utils/reactionCleanupTracking";
21import { isUsingStaticRendering } from "./staticRendering";
22function observerComponentNameFor(baseComponentName) {
23 return "observer".concat(baseComponentName);
24}
25/**
26 * We use class to make it easier to detect in heap snapshots by name
27 */
28var ObjectToBeRetainedByReact = /** @class */ (function () {
29 function ObjectToBeRetainedByReact() {
30 }
31 return ObjectToBeRetainedByReact;
32}());
33function objectToBeRetainedByReactFactory() {
34 return new ObjectToBeRetainedByReact();
35}
36export function useObserver(fn, baseComponentName) {
37 if (baseComponentName === void 0) { baseComponentName = "observed"; }
38 if (isUsingStaticRendering()) {
39 return fn();
40 }
41 var _a = __read(React.useState(objectToBeRetainedByReactFactory), 1), objectRetainedByReact = _a[0];
42 // Force update, see #2982
43 var _b = __read(React.useState(), 2), setState = _b[1];
44 var forceUpdate = function () { return setState([]); };
45 // StrictMode/ConcurrentMode/Suspense may mean that our component is
46 // rendered and abandoned multiple times, so we need to track leaked
47 // Reactions.
48 var reactionTrackingRef = React.useRef(null);
49 if (!reactionTrackingRef.current) {
50 // First render for this component (or first time since a previous
51 // reaction from an abandoned render was disposed).
52 var newReaction = new Reaction(observerComponentNameFor(baseComponentName), function () {
53 // Observable has changed, meaning we want to re-render
54 // BUT if we're a component that hasn't yet got to the useEffect()
55 // stage, we might be a component that _started_ to render, but
56 // got dropped, and we don't want to make state changes then.
57 // (It triggers warnings in StrictMode, for a start.)
58 if (trackingData_1.mounted) {
59 // We have reached useEffect(), so we're mounted, and can trigger an update
60 forceUpdate();
61 }
62 else {
63 // We haven't yet reached useEffect(), so we'll need to trigger a re-render
64 // when (and if) useEffect() arrives.
65 trackingData_1.changedBeforeMount = true;
66 }
67 });
68 var trackingData_1 = addReactionToTrack(reactionTrackingRef, newReaction, objectRetainedByReact);
69 }
70 var reaction = reactionTrackingRef.current.reaction;
71 React.useDebugValue(reaction, printDebugValue);
72 React.useEffect(function () {
73 // Called on first mount only
74 recordReactionAsCommitted(reactionTrackingRef);
75 if (reactionTrackingRef.current) {
76 // Great. We've already got our reaction from our render;
77 // all we need to do is to record that it's now mounted,
78 // to allow future observable changes to trigger re-renders
79 reactionTrackingRef.current.mounted = true;
80 // Got a change before first mount, force an update
81 if (reactionTrackingRef.current.changedBeforeMount) {
82 reactionTrackingRef.current.changedBeforeMount = false;
83 forceUpdate();
84 }
85 }
86 else {
87 // The reaction we set up in our render has been disposed.
88 // This can be due to bad timings of renderings, e.g. our
89 // component was paused for a _very_ long time, and our
90 // reaction got cleaned up
91 // Re-create the reaction
92 reactionTrackingRef.current = {
93 reaction: new Reaction(observerComponentNameFor(baseComponentName), function () {
94 // We've definitely already been mounted at this point
95 forceUpdate();
96 }),
97 mounted: true,
98 changedBeforeMount: false,
99 cleanAt: Infinity
100 };
101 forceUpdate();
102 }
103 return function () {
104 reactionTrackingRef.current.reaction.dispose();
105 reactionTrackingRef.current = null;
106 };
107 }, []);
108 // render the original component, but have the
109 // reaction track the observables, so that rendering
110 // can be invalidated (see above) once a dependency changes
111 var rendering;
112 var exception;
113 reaction.track(function () {
114 try {
115 rendering = fn();
116 }
117 catch (e) {
118 exception = e;
119 }
120 });
121 if (exception) {
122 throw exception; // re-throw any exceptions caught during rendering
123 }
124 return rendering;
125}
126//# sourceMappingURL=useObserver.js.map
\No newline at end of file