parent
4caaf3bdda
commit
76fa37e466
2 changed files with 55 additions and 0 deletions
@ -0,0 +1,30 @@ |
||||
import { useEffect, useRef } from 'react'; |
||||
|
||||
// Allow any function as callback in the protect function.
|
||||
// Could be used to wrap async callbacks to prevent them from running after
|
||||
// component unmount.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type AnyFunction = (...args: any[]) => any; |
||||
|
||||
type ProtectFunction = <F extends AnyFunction>( |
||||
fn: F, |
||||
...args: Parameters<F> |
||||
) => ReturnType<F>; |
||||
|
||||
const useProtect = (): { protect: ProtectFunction } => { |
||||
const isComponentMountedRef = useRef<boolean>(true); |
||||
|
||||
useEffect( |
||||
() => () => { |
||||
isComponentMountedRef.current = false; |
||||
}, |
||||
[], |
||||
); |
||||
|
||||
return { |
||||
protect: (fn, ...args) => |
||||
isComponentMountedRef.current ? fn(...args) : undefined, |
||||
}; |
||||
}; |
||||
|
||||
export default useProtect; |
@ -0,0 +1,25 @@ |
||||
import { Dispatch, SetStateAction, useState } from 'react'; |
||||
|
||||
type SetStateFunction<S> = Dispatch<SetStateAction<S>>; |
||||
|
||||
type SetStateParameters<S> = Parameters<SetStateFunction<S>>; |
||||
|
||||
type SetStateReturnType<S> = ReturnType<SetStateFunction<S>>; |
||||
|
||||
const useProtectedState = <S>( |
||||
initialState: S | (() => S), |
||||
protect: ( |
||||
fn: SetStateFunction<S>, |
||||
...args: SetStateParameters<S> |
||||
) => SetStateReturnType<S>, |
||||
): [S, SetStateFunction<S>] => { |
||||
const [state, setState] = useState<S>(initialState); |
||||
|
||||
return [ |
||||
state, |
||||
(...args: SetStateParameters<S>): SetStateReturnType<S> => |
||||
protect(setState, ...args), |
||||
]; |
||||
}; |
||||
|
||||
export default useProtectedState; |
Loading…
Reference in new issue