Controllable State Hook
lyminhnghia/use-controllable-stateFreeHook
lyminhnghia publishes no description for this item.
Install it
npx shadcn@latest add https://lyminhnghia.github.io/r/use-controllable-state.jsonSource
1/* eslint-disable @typescript-eslint/no-explicit-any */2// This code comes from https://github.com/radix-ui/primitives/blob/main/packages/react/use-controllable-state/src/use-controllable-state.tsx34import * as React from "react"56import { useLayoutEffect } from "@/hooks/use-layout-effect"78// Prevent bundlers from trying to optimize the import9const useInsertionEffect: typeof useLayoutEffect =10 (React as any)[" useInsertionEffect ".trim().toString()] || useLayoutEffect1112type ChangeHandler<T> = (state: T) => void13type SetStateFn<T> = React.Dispatch<React.SetStateAction<T>>1415interface UseControllableStateParams<T> {16 prop?: T | undefined17 defaultProp: T18 onChange?: ChangeHandler<T>19 caller?: string20}2122export function useControllableState<T>({23 prop,24 defaultProp,25 onChange = () => {},26 caller,27}: UseControllableStateParams<T>): [T, SetStateFn<T>] {28 const [uncontrolledProp, setUncontrolledProp, onChangeRef] =29 useUncontrolledState({30 defaultProp,31 onChange,32 })33 const isControlled = prop !== undefined34 const value = isControlled ? prop : uncontrolledProp3536 // OK to disable conditionally calling hooks here because they will always run37 // consistently in the same environment. Bundlers should be able to remove the38 // code block entirely in production.39 /* eslint-disable react-hooks/rules-of-hooks */40 if (process.env.NODE_ENV !== "production") {41 const isControlledRef = React.useRef(prop !== undefined)42 React.useEffect(() => {43 const wasControlled = isControlledRef.current44 if (wasControlled !== isControlled) {45 const from = wasControlled ? "controlled" : "uncontrolled"46 const to = isControlled ? "controlled" : "uncontrolled"47 console.warn(48 `${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`49 )50 }51 isControlledRef.current = isControlled52 }, [isControlled, caller])53 }54 /* eslint-enable react-hooks/rules-of-hooks */5556 const setValue = React.useCallback<SetStateFn<T>>(57 (nextValue) => {58 if (isControlled) {59 const value = isFunction(nextValue) ? nextValue(prop) : nextValue60 if (value !== prop) {61 onChangeRef.current?.(value)62 }63 } else {64 setUncontrolledProp(nextValue)65 }66 },67 [isControlled, prop, setUncontrolledProp, onChangeRef]68 )6970// … truncated
Files it writes
More from lyminhnghia
All 26 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Sound Hookuse-sound | lyminhnghia | Hooks | Free | no deps |
