feat: add useCombinedRefs hook
This commit is contained in:
parent
126050912c
commit
e427da99e3
1
src/shared/hooks/index.ts
Normal file
1
src/shared/hooks/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as useCombinedRefs } from './useCombineRef';
|
||||||
55
src/shared/hooks/useCombineRef.tsx
Normal file
55
src/shared/hooks/useCombineRef.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* A combined ref implementation using the callback ref cleanups feature.
|
||||||
|
* Note that this won't work yet as callback ref cleanups feature isn't released yet and thought to be released in React 19
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import type { ForwardedRef } from 'react';
|
||||||
|
|
||||||
|
type OptionalRef<T> = ForwardedRef<T> | undefined;
|
||||||
|
|
||||||
|
type Cleanup = (() => void) | undefined;
|
||||||
|
|
||||||
|
const setRef = <T,>(ref: OptionalRef<T>, value: T): Cleanup => {
|
||||||
|
if (typeof ref === 'function') {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
||||||
|
const cleanup = ref(value);
|
||||||
|
|
||||||
|
if (typeof cleanup === 'function') {
|
||||||
|
return cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @stylistic/max-statements-per-line
|
||||||
|
return () => { ref(null); };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ref) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
ref.current = value;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-param-reassign,no-return-assign
|
||||||
|
return () => ref.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undefined
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useCombinedRefs = <T,>(...refs: OptionalRef<T>[]) => useCallback((value: T | null) => {
|
||||||
|
const cleanups: Cleanup[] = [];
|
||||||
|
|
||||||
|
for (const ref of refs) {
|
||||||
|
const cleanup = setRef(ref, value);
|
||||||
|
cleanups.push(cleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
for (const cleanup of cleanups) {
|
||||||
|
cleanup?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, refs);
|
||||||
|
|
||||||
|
export default useCombinedRefs;
|
||||||
Loading…
x
Reference in New Issue
Block a user