UNPKG

@loke/ui

Version:
2 lines (1 loc) 1.72 kB
import{useLayoutEffect}from"@loke/ui/use-layout-effect";import React,{useCallback,useEffect,useRef,useState}from"react";var useInsertionEffect=React[" useInsertionEffect ".trim().toString()]||useLayoutEffect;function useControllableState({prop,defaultProp,onChange=()=>{},caller}){let[uncontrolledProp,setUncontrolledProp,onChangeRef]=useUncontrolledState({defaultProp,onChange}),isControlled=prop!==void 0,value=isControlled?prop:uncontrolledProp;if(process.env.NODE_ENV!=="production"){let isControlledRef=useRef(prop!==void 0);useEffect(()=>{let wasControlled=isControlledRef.current;if(wasControlled!==isControlled)console.warn(`${caller} is changing from ${wasControlled?"controlled":"uncontrolled"} to ${isControlled?"controlled":"uncontrolled"}. 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.`);isControlledRef.current=isControlled},[isControlled,caller])}let setValue=useCallback((nextValue)=>{if(isControlled){let v=isFunction(nextValue)?nextValue(prop):nextValue;if(v!==prop)onChangeRef.current?.(v)}else setUncontrolledProp(nextValue)},[isControlled,prop,setUncontrolledProp,onChangeRef]);return[value,setValue]}function useUncontrolledState({defaultProp,onChange}){let[value,setValue]=useState(defaultProp),prevValueRef=useRef(value),onChangeRef=useRef(onChange);return useInsertionEffect(()=>{onChangeRef.current=onChange},[onChange]),useEffect(()=>{if(prevValueRef.current!==value)onChangeRef.current?.(value),prevValueRef.current=value},[value,prevValueRef]),[value,setValue,onChangeRef]}function isFunction(value){return typeof value==="function"}export{useControllableState};