Skip to content

Instantly share code, notes, and snippets.

@luo3house
Created October 10, 2022 03:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luo3house/7a01203f54ff45cadf96c443fc9fadbe to your computer and use it in GitHub Desktop.
Save luo3house/7a01203f54ff45cadf96c443fc9fadbe to your computer and use it in GitHub Desktop.
mobx-react-lite: useObserver completely follow component effects
import { getDependencyTree, Reaction } from "mobx"
import React, { useRef, useState, useLayoutEffect } from "react"
import { isUsingStaticRendering } from "./staticRendering"
import { printDebugValue } from "./utils/printDebugValue"
function observerComponentNameFor(baseComponentName: string) {
return `observer${baseComponentName}`
}
function useMyObserverWithReaction<T>(fn: () => T, baseComponentName: string = "observed"): any {
if (isUsingStaticRendering()) {
return fn()
}
const reactionRef = useRef<Reaction | null>(null)
const [_, setState] = useState([])
const forceUpdate = () => setState([])
useLayoutEffect(() => {
const reaction = new Reaction(observerComponentNameFor(baseComponentName), () => {
forceUpdate()
})
reactionRef.current = reaction
forceUpdate()
return () => {
reaction.dispose()
reactionRef.current = null
}
}, [0])
const reaction = reactionRef.current
React.useDebugValue<Reaction | null>(
reaction,
reaction => reaction && printDebugValue(reaction)
)
let rendering: any = null
if (reaction) {
reaction.track(() => (rendering = fn()))
} else {
rendering = fn() // keep hooks
}
return rendering
}
export { useMyObserverWithReaction as useObserver }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment