For a long while we there were norefs
- we had onlyref
, which was callback based. Something will set aref
by calling it.
classExampleextendsReact.Component{state={ref1:null,}ref2=null;// updating ref1 would trigger update for this componentsetRef1=(ref)=>this.setState(ref1);// updating ref2 would just set itsetRef2=(ref)=>this.ref2=ref;render(){return<divref={ref1}><spanref={ref2}>🤷♂️</span></div>}
That was what we were doing for ages, untilcreateRef
comes to the game.React.createRef
is more aboutref2
way - current ref wouldjust set to, well,ref.current
.
Keep in mind thatuseRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render.
So -If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to usea callback ref instead. Ie the old way to _ref.
constExample=()=>{const[ref,setRef]=useState(null);constonRefSet=useCallback(ref=>{setRef(ref);ref.current.focus();// a side effect!});// well, you can rereturn<divref={onRefSet}>😎</div>}
But later you might try to combine ref-refs and callbacks-refs, and... well that's the road to 🔥hell🔥.
In addition - there isuseImperativeHandle whichpartially could controlref propagation, but every time I was used to use it - it was just a 💩disaster💩.
functionFancyInput(props,ref){constinputRef=useRef(null);useImperativeHandle(ref,()=>({focus:()=>{inputRef.current.focus();// it just does not usually works :P}}));return<inputref={inputRef}.../>;}FancyInput=forwardRef(FancyInput);
LET'S FIX IT!
Introducinguse-callback-ref - the samecreateRef
anduseRef
, but with callback built in.
import{useCallbackRef}from'use-callback-ref';constExample=()=>{constref=useCallbackRef(null,ref=>ref&&ref.focus());// that's allreturn<divref={ref}>😎</div>}
It's literally the old goodref
with anon-change callback, nothing more.
Why not to use callback-based ref? Well, it's much easier to handle one interface, which would be accessible thought all components that ref would be passed, well, thought - while with
setRef
onlycallback
would be visible for transitional components. However, that could be a good from isolation point of view.
This simple approach could also help withuseImperativeHandle
case:
functionFancyInput(props,ref){constinputRef=useCallbackRef(null,(newValue)=>{// notice - this code is __isolated__, and you can move it off this componentref.current={focus:()=>newValue.focus()}// as long as you don't need to use callback-ref anymore - we could simply this case.});return<inputref={inputRef}.../>;}FancyInput=forwardRef(FancyInput);
So - Keep in mind thatuseRef 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 useCallbackRef instead.
- 300b, and IE11 support
- based on getters and setters, no Proxies involved
Try it now(codesandbox demo), and call me back later -https://github.com/theKashey/use-callback-ref
And there is the second part of this article
Top comments(1)

- LocationLas Vegas
- WorkSenior Developer
- Joined
This completely solved my issue with connecting Greensock to React-Pixi components.
For further actions, you may consider blocking this person and/orreporting abuse