Skip to content

Instantly share code, notes, and snippets.

@shakhzodkudratov
Created July 26, 2024 15:12
Show Gist options
  • Save shakhzodkudratov/e284e7e3644ab3a8a754ae32a4e61932 to your computer and use it in GitHub Desktop.
Save shakhzodkudratov/e284e7e3644ab3a8a754ae32a4e61932 to your computer and use it in GitHub Desktop.
unref all refs safely
import type { RefObject } from "react";
type UnrefType<T> = T extends RefObject<infer RT> ? RT : never;
type UnrefTuple<Tuple extends [...unknown[]]> = {
[Index in keyof Tuple]: UnrefType<Tuple[Index]>;
} & { length: Tuple["length"] };
type FnRet = void | Promise<void>;
export function getRefs<T extends [...RefObject<unknown>[]]>(
refs: [...T],
fn: (els: UnrefTuple<T>) => FnRet,
): FnRet {
const items = refs.map((ref) => ref.current).filter((el) => el != null);
if (items.length === refs.length) {
return fn(items as Parameters<typeof fn>["0"]);
}
}
// example usage
export const TextComponent2: React.FC = () => {
const groupRef = React.useRef<HTMLDivElement>(null); // here you have refs declared with concrete types
const textRef = React.useRef<HTMLSpanElement>(null);
React.useEffect(() => {
getRefs(
// input:
// RefObject<HTMLSpanElement>, RefObject<HTMLDivElement>;
[textRef, groupRef],
// output:
// HTMLSpanElement, HTMLDivElement
([textEl, groupEl]) => {
console.log(textEl, groupEl);
},
);
}, []);
return (
<div ref={groupRef}>
<span ref={textRef}>I am the text</span>
</div>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment