use-callback-ref
use-callback-ref copied to clipboard
π€The same useRef, but it will callback
π€ use-callback-ref π
The same `useRef` but it will callback: π Hello! Your ref was changed!
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:
- https://dev.to/thekashey/the-same-useref-but-it-will-callback-8bo
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
π‘ Some commands are hooks based, and returns the same refs/functions every render. But some are not, to be used in classes or non-react code.
useRef API
π€ Use case: every time you have to react to ref change
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 providedcallbackwhen ref is changed.
useCallbackRef - to replace React.useRef
useCallbackRef(initialValue, callback)- would call providedcallbackwhen ref is changed.
callbackin 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
}
π‘ You can use 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
π€ Use case: every time you need to assign ref manually, and you dont know the shape of the ref
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)
π€ Use case: ref could be different.
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 -
applyRefsis simular tomergeRef,applyRefis similar toassignRef - useForkRef -
useForkRefis simular touseMergeRefs, but accepts only two arguments. - react-merge-refs -
merge-refsis simular touseMergeRefs, but not a hook and does not provide "stable" reference.
Is it a rocket science? No,
RefObjectis no more than{current: ref}, anduse-callback-refis no more thangetterandsetteron that field.
License
MIT