Last active
May 25, 2024 12:30
-
-
Save Misaka-0x447f/18cc14320abf8da37201863865df5047 to your computer and use it in GitHub Desktop.
useHybridState.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { isFunction } from 'lodash-es' | |
import { | |
useCallback, | |
useRef, | |
useState, | |
useMemo, | |
Dispatch, | |
SetStateAction, | |
DependencyList, | |
useEffect | |
} from 'react' | |
export const useHybridState = <T>(initialValue?: T | undefined) => { | |
const [state, setState] = useState(initialValue as T) | |
const ref = useRef(initialValue) | |
const set = useCallback((val: T) => { | |
if (isFunction(val)) { | |
ref.current = val(ref.current) | |
} else { | |
ref.current = val | |
} | |
setState(val) | |
}, []) | |
const refBehindProxy = useMemo( | |
() => | |
new Proxy(ref, { | |
set: () => { | |
throw new Error( | |
"Do not change value of this ref, it's readonly. Instead, use the set method." | |
) | |
} | |
}), | |
[] | |
) | |
return [state, set, refBehindProxy] as [ | |
typeof state, | |
Dispatch<SetStateAction<T>>, | |
{ | |
readonly current: T | |
} | |
] | |
} | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
export const useHybridUpdateState = <T>(initialValue: T | undefined) => { | |
const [state, setState, stateRef] = useHybridState<T>(initialValue) | |
const updateState = (partialState: Partial<T>) => { | |
setState((prevState) => Object.assign({}, prevState, partialState)) | |
} | |
return [state, updateState, stateRef, setState] as const | |
} | |
export const useHybridMemo = <T>(factory: () => T, deps: DependencyList | undefined) => { | |
const [state, setState, stateRef] = useHybridState<T>() | |
useEffect(() => { | |
setState(factory()) | |
}, deps) | |
return [state, stateRef] as const | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment