create-effect-with-target
shadcn-hooks/create-effect-with-targetFreeUtility
A hook to create an effect with a target.
Install it
npx shadcn@latest add https://shadcn-hooks.com/r/create-effect-with-target.jsonSource
1import { isBrowser, isEqual, isFunction } from 'es-toolkit'2import { useRef } from 'react'3import { useUnmount } from '@/registry/hooks/use-unmount'4import type {5 DependencyList,6 EffectCallback,7 RefObject,8 useEffect,9 useLayoutEffect,10} from 'react'1112type TargetValue<T> = T | undefined | null1314type TargetType = HTMLElement | Element | Window | Document1516export type BasicTarget<T extends TargetType = Element> =17 | (() => TargetValue<T>)18 | TargetValue<T>19 | RefObject<TargetValue<T>>2021export function getTargetElement<T extends TargetType>(22 target: BasicTarget<T>,23 defaultElement?: T,24) {25 if (!isBrowser) {26 return undefined27 }2829 if (!target) {30 return defaultElement31 }3233 let targetElement: TargetValue<T>3435 if (isFunction(target)) {36 targetElement = target()37 } else if ('current' in target) {38 targetElement = target.current39 } else {40 targetElement = target41 }4243 return targetElement44}4546export function createEffectWithTarget(47 useEffectType: typeof useEffect | typeof useLayoutEffect,48) {49 /**50 *51 * @param effect52 * @param deps53 * @param target target should compare ref.current vs ref.current, dom vs dom, ()=>dom vs ()=>dom54 */55 const useEffectWithTarget = (56 effect: EffectCallback,57 deps: DependencyList,58 target: BasicTarget<any> | BasicTarget<any>[],59 ) => {60 const hasInitRef = useRef(false)6162 const lastElementRef = useRef<(Element | null)[]>([])63 const lastDepsRef = useRef<DependencyList>([])6465 const unLoadRef = useRef<any>(undefined)6667 useEffectType(() => {68 const targets = Array.isArray(target) ? target : [target]69 const els = targets.map((item) => getTargetElement(item))7071 // init run72 if (!hasInitRef.current) {73 hasInitRef.current = true74 lastElementRef.current = els75 lastDepsRef.current = deps7677 unLoadRef.current = effect()78 return79 }8081 if (82 els.length !== lastElementRef.current.length ||83 !isEqual(lastElementRef.current, els) ||84 !isEqual(lastDepsRef.current, deps)85 ) {86 unLoadRef.current?.()8788 lastElementRef.current = els89 lastDepsRef.current = deps90 unLoadRef.current = effect()91 }92 })9394 useUnmount(() => {95 unLoadRef.current?.()96 // for react-refresh97 hasInitRef.current = false98 })99 }100101 return useEffectWithTarget102}
What it pulls in
npm packages
Other registry items
Files it writes
More from shadcn-hooks
All 58 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| create-contextcreate-context | shadcn-hooks | Utilities | Free | no deps | |
| is-browseris-browser | shadcn-hooks | Utilities | Free | no deps |
