Hello, guys. In this article, I want to share with you about React useRef
and forwardRef
hooks, but this article is not about what are react hooks, when they were created and why we should use them.
So, if you are not familiar with react hooks or with react, you should read about what is react, what is hooks, and play with simple hooks such as useState
, useEffect
, and after you can go back here.
The purpose of useRef
is to keep variables between rerendering react components. As you know, during each render all variables and functions will recreate. And for example, if you want to keep some value during rerenders, change it only when you need it, you can use useRef
it for this purpose.
And you can ask, why we need useRef
if we have useState
that could keep value between rerenders and we can change this value at any time. The answer is yes, you can. But if you change your state, the component, which uses this state will rerender. Instead of useState
, changing useRef
value doesn’t make rerender.
Let’s check how useRef
works and then we compare useRef
and useState
.
As you can see, creating ref is almost as useState
, but it returns just one value, without a setter. Let’s check what value will be inside our ref:
useRef
will return an object with a property current
that contains an initial value, that you can pass during initialization useRef
.
Let’s say, we want to change our value name. You can do it really simple:
Changing the name, inside ref, will not run page rerendering.
Let’s compare useRef
with useState
. I will add useEffect
, setInterval
with use ref changing there every 300 milliseconds:
As we can see our rendering doesn’t call every 300 milliseconds.
But let’s do the same with useState
:
Our setUserState
calls rerender every 300 milliseconds.
Knowing this, if you want to keep some value, change it, but you don’t want rerenders you can use useRef
hook. It’s like a this
in class component, when you change some property using this
keyword instead of calling this.setState()
in class component.
And now, let’s check an example with the most common usage of useRef on practice:
Imagine that you have some editor (textarea) on the page and you want to make focus as soon, as a user sees this textarea on the page. How can you do this?
In pure Javascript you can do something like:
const textarea = document.querySelector(‘#editor‘);
textarea.focus();
But how does it in react? For this purpose, you should use useRef and attach it to the DOM element. Let’s check an example:
As you can see here, it’s really simple. You create userRef
and pass it to DOM element, using attribute ref: <textarea ref={textareaRef} />
You can set ref to elements, and then works as with a simple DOM API. like, add focus, addEventListener
, removeEventListener
.
To get access to this ref, use another hook, useEffect
as you can see in the picture. In this case, you can be sure that DOM element was created.
Using useRef
is more imperative way of working with DOM and in general, if you can, use react API, instead of native DOM API. But sometimes, we don’t have the ability to make something using only react API. For such cases, using ref and native DOM API is fine.
For example, if you use an external library, that doesn’t work with react, but you need somehow connect this library to DOM element (google maps or chart.js), useRef
and native DOM API is a good solution. Fortunately, many modern libraries have react wrappers, so you can use them.
Another example, if you need coordinates from some element, you can set useRef
to that element and call getBoundingClientRect
method.
The important thing: as a ref, you can use only native DOM elements, if you put ref to your own component, it will not work.
This will not work:
In this example, textareaRef.current contains the default value, which is null.
But what, if you want to pass this ref as a prop to the child component? Like at the example below:
Unfortunately, this also doesn’t work.
But there is a solution. If you want to make a reusable component and pass ref from a parent to children, you can use forwardRef
.
forwardRef
is a HOC, that accepts components as a parameter. And, inside this component, we have access to props (the first param) and to the ref (the second param). Let’s take a look:
As you can see, forwardRef
is just a function, that is imported from react. This function takes a component as a param. That component has the first param is props, and the second is ref from a parent component.
And as you can see, we should also set the display name, because forwardRef
clears it. How to use this component from the parent?
You can use this component, which is wrapped with forwarRef
as a just simple component, but here, we pass ref as a prop. For example, as you can see, we created 2 textarea
and 2 useRef
. Inside useEffect you can have some conditions and decide what you want to do with any of that refs.
In general, that’s all that you should know before starting work with useRef
and forwardRef
.
Try to play with both of them. In practice, it is not a very common thing that you will use, but sometimes, when react API is not enough they are really useful.
Let’s summarize everything, that we know about useRef
and forwardRef
:
useRef
is often used as a reference to some DOM element, when react API is not enough.useEffect
to be sure that DOM element was created on the page.useRef
can be used also if you want to have a variable, that will keep some information between rendering and you don’t want to call page rerendering after changing this variable (unlike useState).useRef
could be used only on native DOM elements (HTML tags).forwardRef
HOC. And don’t forget to change the displayName
of your component, after using forwardRef
.