Keep in mind that useRef doesn't notify you when its content changes. Mutating the .current property doesn't cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use
a callback ref instead.... useCallbackRef instead.
Read more about use-callback
pattern and use cases:
This library exposes helpers to handle any case related to ref
lifecycle
useCallbackRef
- react on hook changemergeRefs
- merge multiple refs together. For, actually, forktransformRef
- transform one ref to antherrefToCallback
- convert RefObject to an old callback-style refassignRef
- assign value to the ref, regardless of it's form
All functions are tree shakable, but even together it's less then 300b.
API
useRef API
API is 99% compatible with React createRef
and useRef
, and just adds another argument - callback
,
which would be called on ref update.
createCallbackRef - to replace React.createRef
createCallbackRef(callback)
- would call providedcallback
when ref is changed.
useCallbackRef - to replace React.useRef
useCallbackRef(initialValue, callback)
- would call providedcallback
when ref is changed.
callback
in both cases iscallback(newValue, oldValue)
. Callback would not be called if newValue and oldValue is the same.
import {useRef, createRef, useState} from 'react';
import {useCallbackRef, createCallbackRef} from 'use-callback-ref';
const Component = () => {
const [,forceUpdate] = useState();
// I dont need callback when ref changes
const ref = useRef(null);
// but sometimes - it could be what you need
const anotherRef = useCallbackRef(null, () => forceUpdate());
useEffect( () => {
// now it's just possible
}, [anotherRef.current]) // react to dom node change
}
useCallbackRef
to convert RefObject into RefCallback, creating bridges between the old and the new code
// some old component
const onRefUpdate = (newValue) => {...}
const refObject = useCallbackRef(null, onRefUpdate);
// ...
<SomeNewComponent ref={refObject}/>
assignRef
assignRef(ref, value)
- assigns values
to the ref
. ref
could be RefObject or RefCallback.
🚫 ref.current = value // what if it's a callback-ref?
🚫 ref(value) // but what if it's a object ref?
import {assignRef} from "use-callback-ref";
✅ assignRef(ref, value);
useTransformRef (to replace React.useImperativeHandle)
transformRef(ref, tranformer):Ref
- return a new ref
which would propagate all changes to the provided ref
with applied transform
// before
const ResizableWithRef = forwardRef((props, ref) =>
<Resizable {...props} ref={i => i && ref(i.resizable)}/>
);
// after
const ResizableWithRef = forwardRef((props, ref) =>
<Resizable {...props} ref={transformRef(ref, i => i ? i.resizable : null)}/>
);
refToCallback
refToCallback(ref: RefObject): RefCallback
- for compatibility between the old and the new code.
For the compatibility between RefCallback
and RefObject use useCallbackRef(undefined, callback)
useMergeRefs
mergeRefs(refs: arrayOfRefs, [defaultValue]):ReactMutableRef
- merges a few refs together
When developing low level UI components, it is common to have to use a local ref but also support an external one using React.forwardRef. Natively, React does not offer a way to set two refs inside the ref property. This is the goal of this small utility.
import React from 'react'
import {useMergeRefs} from 'use-callback-ref'
const MergedComponent = React.forwardRef((props, ref) => {
const localRef = React.useRef();
// ...
// both localRef and ref would be populated with the `ref` to a `div`
return <div ref={useMergeRefs([localRef, ref])} />
})
useMergeRefs
will always give you the same return, and you don't have to worry about [localRef, ref]
unique every render.
mergeRefs
mergeRefs(refs: arrayOfRefs, [defaultValue]):ReactMutableRef
- merges a few refs together
is a non-hook based version. Will produce the new ref
every run, causing the old one to unmount, and be populated with the null
value.
mergeRefs are based on https://github.com/smooth-code/react-merge-refs, just exposes a RefObject, instead of a callback
mergeRefs
are "safe" to use as a part of other hooks-based commands, but don't forget - it returns a new object every call.
Similar packages:
- apply-ref -
applyRefs
is simular tomergeRef
,applyRef
is similar toassignRef
- useForkRef -
useForkRef
is simular touseMergeRefs
, but accepts only two arguments. - react-merge-refs -
merge-refs
is simular touseMergeRefs
, but not a hook and does not provide "stable" reference.
Is it a rocket science? No,
RefObject
is no more than{current: ref}
, anduse-callback-ref
is no more thangetter
andsetter
on that field.
License
MIT