react-use-ref-map
v1.0.2
Published
Multiple React ref management utility.
Downloads
39
Readme
react-use-ref-map
Install
npm
npm install react-use-ref-map
Yarn
yarn add react-use-ref-map
Rationale
Currently, it is possible to:
- Keep a variable amount of refs inside a single
useRef
, without being easily informed when and which ref is added or removed.- For example,
useClickAwayListener
- we might want to ignore multiple refs whose amount changes over rerenders, but we don't need to know about their mounts/unmounts (the listener is attached to the window/document).
- For example,
- Keep a non-variable amount of refs by using the callback form of a ref (
useCallback
instead ofuseRef
). Due to Rules of Hooks,useCallback
may not be called a variable amount of times.- For example,
useIntersectionObserver
- we are interested in only one ref and we want to know when it mounts/mounts, souseCallback
is ideal.
- For example,
However, it is not possible to concisely keep a variable amount of refs and be informed of their addition or removal, while also keeping functions' identities to preserve memoization.
Take useMouseLeaveListener
for an example - a hook that tells when the user leaves an area. The area might be complex, consisting of multiple root elements.
- The amount of parents might be variable (nested popups and so on).
- You want to be aware when any of them mounts/unmounts, so
mouseleave
listeners are added and removed accordingly.
Usage
Variable amount of refs:
function Component() {
/* State may change over renders. */
const [state, setState] = useState(["A", "B", "C", "D"]);
const [setRef, refs] = useRefMap();
return (
<>
{state.map((letter) => (
<div key={letter} ref={setRef(letter)}>
{letter}
</div>
))}
</>
);
}
Variable amount of refs, listen to mounts/mounts:
function Component() {
const [state, setState] = useState(["A", "B", "C", "D"]);
const [addRef, refs] = useRefMap({
onEnter: (key, element, refs) => {
element.addEventListener("mouseleave", listener);
},
onLeave: (key, element, refs) => {
element.removeEventListener("mouseleave", listener);
if (!Object.values(refs.current).length) console.log("Refs are empty!");
},
});
return (
<>
{state.map((letter) => (
<div key={letter} ref={setRef(letter)}>
{letter}
</div>
))}
</>
);
}
Though less useful, non-variable amount of refs
function Component() {
const [setRef, refs] = useRefMap();
console.log(refs.current["outer"]); // HTMLDivElement
return (
<div ref={setRef("outer")}>
<div ref={setRef("inner1")} />
<div ref={setRef("inner2")} />
</div>
);
}