Skip to content

Instantly share code, notes, and snippets.

@modernserf
Last active May 25, 2019 14:04
Show Gist options
  • Save modernserf/6e1534d84e219858ec23d5578921e5a3 to your computer and use it in GitHub Desktop.
Save modernserf/6e1534d84e219858ec23d5578921e5a3 to your computer and use it in GitHub Desktop.
Two approaches to handling imperative code in react
function useTransition (isActive, onEnter = noop, onExit = noop) {
const ref = useRef()
useEffect(() => {
if (!ref.current) return
if (isActive) onEnter(ref.current) else onExit(ref.current)
}, [isActive])
return ref
}
// -----
function ScrollIntoViewContainer ({ isActive, children }) {
const ref = useTransition(isActive, (el) => el.scrollIntoView())
return <div ref={ref}>{children}</div>
}
const Context = createContext()
function NamedImperativeController ({ children }) {
const [refs, setRefs] = useState({})
const value = useMemo(() => ({
registerRef: (name, ref) => {
if (refs[name]) throw new Error(`Already a ref with name ${name}`)
setRefs(prev => ({ ...prev, [name]: ref }))
return () => setRefs(prev => ({ ...prev, [name]: undefined }))
},
getNamedRef: (name, onError=null) => {
if (refs[name]) return refs[name]
if (onError) return onError(refs)
throw new Error(`No ref with name ${name}`)
}
}), [refs])
return <Context.Provider value={value}>{children}</Context.Provider>
}
function useNamedRef (name) {
const ref = useRef()
const { registerRef } = useContext(Context)
useEffect(() => registerRef(name, ref), [name])
return ref
}
function useGetNamedRef (name, orDefault) {
const { getNamedRef } = useContext(Context)
return getNamedRef(name, orDefault)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment