React useRef, forwardRef and Some Problems you May Run Into Working With Them

Written by serhiirubets | Published 2022/05/22
Tech Story Tags: react | react-hook | useref | react-hooks | reacthooks | react-function-components | debugging | getsentry

TLDRIn this article, I want to share with you about React `useRef` and `forwardRef` hooks. This article is not about what are react hooks, when they were created and why we should use them. If you are not familiar with react hooks or with react, you should read about react hooks and play with simple hooks such as `useState` and 'useEffect`. The purpose of useRef` is to keep variables between rerendering react components. But if you change your state, the component, which uses this state will rerender.via the TL;DR App

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 useRefif 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, useEffectas 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 useRefto 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.
  • Work with ref inside 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).
  • if you want to pass ref as a prop to the child component, you should wrap your child component into forwardRef HOC. And don’t forget to change the displayName of your component, after using forwardRef.


Written by serhiirubets | I'm a Fullstack JS engineer with 10 years of experience. Also, I'm a mentor, teacher, and author of front-end courses.
Published by HackerNoon on 2022/05/22