UNPKG

mobx-react-lite

Version:

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

91 lines 3.97 kB
import { Reaction } from "mobx"; import React from "react"; import { printDebugValue } from "./utils/printDebugValue"; import { isUsingStaticRendering } from "./staticRendering"; import { observerFinalizationRegistry } from "./utils/observerFinalizationRegistry"; import { useSyncExternalStore } from "use-sync-external-store/shim"; function createReaction(adm) { adm.reaction = new Reaction("observer".concat(adm.name), function () { var _a; adm.stateVersion = Symbol(); // onStoreChange won't be available until the component "mounts". // If state changes in between initial render and mount, // `useSyncExternalStore` should handle that by checking the state version and issuing update. (_a = adm.onStoreChange) === null || _a === void 0 ? void 0 : _a.call(adm); }); } export function useObserver(render, baseComponentName) { if (baseComponentName === void 0) { baseComponentName = "observed"; } if (isUsingStaticRendering()) { return render(); } var admRef = React.useRef(null); if (!admRef.current) { // First render var adm_1 = { reaction: null, onStoreChange: null, stateVersion: Symbol(), name: baseComponentName, subscribe: function (onStoreChange) { // Do NOT access admRef here! observerFinalizationRegistry.unregister(adm_1); adm_1.onStoreChange = onStoreChange; if (!adm_1.reaction) { // We've lost our reaction and therefore all subscriptions, occurs when: // 1. Timer based finalization registry disposed reaction before component mounted. // 2. React "re-mounts" same component without calling render in between (typically <StrictMode>). // We have to recreate reaction and schedule re-render to recreate subscriptions, // even if state did not change. createReaction(adm_1); // `onStoreChange` won't force update if subsequent `getSnapshot` returns same value. // So we make sure that is not the case adm_1.stateVersion = Symbol(); } return function () { var _a; // Do NOT access admRef here! adm_1.onStoreChange = null; (_a = adm_1.reaction) === null || _a === void 0 ? void 0 : _a.dispose(); adm_1.reaction = null; }; }, getSnapshot: function () { // Do NOT access admRef here! return adm_1.stateVersion; } }; admRef.current = adm_1; } var adm = admRef.current; if (!adm.reaction) { // First render or reaction was disposed by registry before subscribe createReaction(adm); // StrictMode/ConcurrentMode/Suspense may mean that our component is // rendered and abandoned multiple times, so we need to track leaked // Reactions. observerFinalizationRegistry.register(admRef, adm, adm); } React.useDebugValue(adm.reaction, printDebugValue); useSyncExternalStore( // Both of these must be stable, otherwise it would keep resubscribing every render. adm.subscribe, adm.getSnapshot, adm.getSnapshot); // render the original component, but have the // reaction track the observables, so that rendering // can be invalidated (see above) once a dependency changes var renderResult; var exception; adm.reaction.track(function () { try { renderResult = render(); } catch (e) { exception = e; } }); if (exception) { throw exception; // re-throw any exceptions caught during rendering } return renderResult; } //# sourceMappingURL=useObserver.js.map