import { Reaction } from "mobx" ; import React from "react" ; import { printDebugValue } from "./utils/printDebugValue" ; import { addReactionToTrack , IReactionTracking , recordReactionAsCommitted } from "./utils/reactionCleanupTracking" ; import { isUsingStaticRendering } from "./staticRendering" ; function observerComponentNameFor ( baseComponentName ) { return `observer${ baseComponentName }` ; } /**
 * We use class to make it easier to detect in heap snapshots by name
 */ class ObjectToBeRetainedByReact { } function objectToBeRetainedByReactFactory ( ) { return new ObjectToBeRetainedByReact ( ) ; } export function useObserver < T > ( fn , baseComponentName = "observed" ) { if ( isUsingStaticRendering ( ) ) { return fn ( ) ; } const [ objectRetainedByReact ] = React . useState ( objectToBeRetainedByReactFactory ) ; const [ , setState ] = React . useState ( ) ; const forceUpdate = ( ) => setState ( [ ] as any ) ; const reactionTrackingRef = React . useRef < IReactionTracking | null > ( null ) ; if ( ! reactionTrackingRef . current ) { const newReaction = new Reaction ( observerComponentNameFor ( baseComponentName ) , ( ) => { if ( trackingData . mounted ) { forceUpdate ( ) ; } else { trackingData . changedBeforeMount = true ; } } ) ; const trackingData = addReactionToTrack ( reactionTrackingRef , newReaction , objectRetainedByReact ) ; } const { reaction } = reactionTrackingRef . current ! ; React . useDebugValue ( reaction , printDebugValue ) ; React . useEffect ( ( ) => { recordReactionAsCommitted ( reactionTrackingRef ) ; if ( reactionTrackingRef . current ) { reactionTrackingRef . current . mounted = true ; if ( reactionTrackingRef . current . changedBeforeMount ) { reactionTrackingRef . current . changedBeforeMount = false ; forceUpdate ( ) ; } } else { reactionTrackingRef . current = { reaction : new Reaction ( observerComponentNameFor ( baseComponentName ) , ( ) => { forceUpdate ( ) ; } ) , mounted : true , changedBeforeMount : false , cleanAt : Infinity } ; forceUpdate ( ) ; } return ( ) => { reactionTrackingRef . current ! . reaction . dispose ( ) ; reactionTrackingRef . current = null ; } ; } , [ ] ) ; let rendering ! ; let exception ; reaction . track ( ( ) => { try { rendering = fn ( ) ; } catch ( e ) { exception = e ; } } ) ; if ( exception ) { throw exception ; } return rendering ; }