One of the usages I see a lot with useEffect in React code is to run some JavaScript code on an element reference which is stored as ref as soon as this element is mounted. For example, when an element is mounted, animate it’s content using Web Animation API.
The following code is doing exactly that:
In the code above, you set the ref to the heading element and when the component is mounted, it’s animating the heading with some premade animation.
That is easy, so why should you bother reading this post at all?
Because there is a better alternative to do exactly the same thing but without useEffect and useRef hooks.
The ref attribute is expecting that you will set it with one of the following types:
RefCallback<T> | RefObject<T> | null
A RefCallback is just a function that accepts the element node and returns void. In a matter of fact, whenever you use RefObject, it’s just a syntactic sugar to set the reference on the element to the current accessor of the useRef created reference. The following code is what is going to happen when you set a ref like in the first code block in this post:
<h1
ref={(node) => {
ref.current = node;
}}
/>
The RefCallback function is going to run after the component is mounted, re-rendered or unmounted.
Now, packed with this knowledge, how you can refactor the above code and stop using useEffect and useRef combination?
The following code will do exactly that:
Let’s try to understand what is going on. In the code, you use the useCallback function with an empty dependency array to wrap the callback ref function. This will make sure that React runtime will run this function only on mount and that is it. No need to use the useRef or useEffect hook and you achieve the same functionality. You gain two adeed bonueses when you use callback ref. The first one is that you don’t get double rendering in development mode like you will get when you use useEffect. The second bonus is that in the case of using forwardRef and conditional rendering, the callback ref code will stay stable and work while the useEffect code might not work as expected if the element isn’t rendered due to the conditional rendering.
If you want to look at the provided code and see how it works, you can play with the previous code in this sandbox:
For further reading about callback refs, you can look at React documentation: https://legacy.reactjs.org/docs/refs-and-the-dom.html#callback-refs