Developer grabbing reference with useRef hook
BCiriak Avatar
by BCiriakJUN 09, 2022 | 9 min read

Using the useRef hook in React

What is the useRef hook and how can we use it in React to solve some use cases? In this article, we will look at a couple of example usages of the useRef hook with JavaScript and TypeScript.

The useRef hook is one of the handy React hooks that we can use to solve some of the problems that other hooks will not solve for us. Let's have a look at what are the use cases that useRef hook can help us with.

useRef in React: Two main use cases

  • grabbing a reference to DOM element to manipulate it as in vanilla JavaScript
  • creating variable "container" that behaves like a mixture of plain variable in component and variable handled by useState

Read this article for more info about `useState`.

You can have a look at the finished code here:

DOM Element Reference and useRef hook

The best way to wrap our heads around these is to look at some code. Here is a basic implementation of the useRef hook grabbing DOM element ref:


We will also look at how to work with useRef and TypeScript in the bonus section of this article.

1import {useRef} from 'react'
3export default function BasicUseRef() {
4  const spanElement = useRef()
6  const changeText = () => {
7    spanElement.current.innerText = 'Hello World 🌍'
8  }
10  return (
11    <div>
12      <button onClick={changeText}>Change Text</button>
13      <span ref={spanElement}>Hi 👋</span>
14    </div>
15  )

After we import useRef from React, we instantiate our spanElement constant that will point to the actual span element. changeText is a function bound to onClick event on our button below in the JSX.

In JSX we are rendering two elements, a button and a span. We grab the reference to the span element with ref={spanElement} and notice the initial text: Hi 👋. Thanks to the reference, we can access native properties and methods (if the element has some) of this DOM element, in our case span, which has property innerText.

When we click on the button, the changeText function fires and changes the text of the span. You might notice we are accessing the innerText through this current property. That is what the useRef hook gives us back, object with current property.


Thing to mention is, that changing the text of the span will not re-render our component. Give it a try, put a console.log right below the const spanElement.

useRef hook as an Instance variable

Now we will have a look at the second use case for useRef hook.

1import {useRef, useState} from 'react'
3export default function Variables() {
4  let vanillaVariable = 'Vanilla' // bad and useless ❌
5  const [useStateVariable, setUseStateVariable] = useState('Chocolate')
6  const useRefVariable = useRef('Strawberry')
8  const changeFlavor = () => {
9    vanillaVariable = 'New Vanilla'
10    setUseStateVariable('New Chocolate')
11    useRefVariable.current = 'New Strawberry'
12  }
14  return (
15    <div>
16      <p><b>vanilla</b> Variable: {vanillaVariable}</p>
17      <p><b>useState</b> Variable: {useStateVariable}</p>
18      <p><b>useRef</b> Variable: {useRefVariable.current}</p>
19      <button onClick={changeFlavor}>New Flavor</button>
20    </div>
21  )

We are declaring variables in three different ways. The first one is a regular JavaScript variable in our component scope, the second is by using useState hook and the last one is by useRef hook.

After we click on the button we want to change our variables to have New prepended to the original text.

Okay, this may be a really simple and dumb example but I want to point out some obvious things that can catch beginners off guard. Especially the first vanillaVariable. Due to how React handles rendering and subsequent re-renders, this variable will never a render New Vanilla text. Simply said, after React re-renders this component, our vanillaVariable will be instantiated again to the Vanilla string. This simple concept is important to understand.

Variables with useState hook

When we click on the button, our useState variable will change to the new text. We see the change on screen thanks to the re-render that React runs after this variable changes and only because of this reason.

Variables with useRef hook

If we look at our useRefVariable, it also changes in the browser but that is misleading. It only happens because we are changing the useStateVariable which causes the re-render. If we remove that setUseStateVariable call from the changeFlavor function, the browser UI will not re-render, hence our useRef variable will not change.

And these are the big differences between these three variables.

useRef will not cause re-render, as our plain JavaScript variable definition but it will hold the new value after re-render, just as our setState variable.

Bonus: useRef and TypeScript examples

The first example is a simple one but there are some heads ups that we need to know, not to get confused when using TypeScript with React hooks.

Why should you use TypeScript instead of JavaScript?
1import {useEffect, useRef} from 'react'
3export default function App() {
4  const spanRef = useRef<HTMLSpanElement>(null)
6  useEffect(() => {
7    if (spanRef.current) {
8      spanRef.current.innerText = "Hello World!"
9    }
10  }, [])
12  return (
13    <div>
14      <span ref={spanRef}>Hello</span>
15    </div>
16  )

There are two things to point out and these are the basics that we need to understand when working with TypeScript. Type declarations and type checking. Once we handle these two, TypeScript is going to give us a ton of benefits.

On the fourth line, we are declaring what type will our spanRef be. And you might be asking, how did I know it's gonna be HTMLSpanElement? Well, I did not just guess it, I have some experience on how to figure these types out. It can get a bit frustrating when you are just starting with TypeScript, but with some practice and experience, it will get simpler.

Have a look at this link to Microsoft website where they list basic DOM Element types.

Looking at line 7, that is where we do our type checking, making sure that our spanRef.current is defined.

useRef hook to bind events

Now we will look at the last example:

1import {useRef} from 'react'
3export default function UseRefElement() {
4  const elementRef = useRef<HTMLButtonElement>(null)
6  const handleClick = () => {
7    if (elementRef.current) {
8      elementRef.current.onclick = () => console.log('doing something')
9    }
10  }
12  return (
13    <div>
14      <button onClick={handleClick}>Bind button</button>
15      <button ref={elementRef}>Ref Button</button>
16    </div>
17  )

This is also a silly example, but it brings home the point of what useRef hook can do. What we do here is, basically, we bind one onClick event by clicking another button.

Notice that on line 8 we are accessing current.onclick property of Button DOM element. That is why the syntax of onclick is not a camel case as we are used to in React. The useRef hook gives us control over the whole DOM element.

Common React interview question: Input Focus

Last example is also quite common React.js interview question. Question is, how would you focus a specific input element in React? Let's see:

1import {useEffect, useRef} from 'react'
3export default function FocusInput() {
4  const inputRef = useRef<HTMLInputElement>(null)
6  useEffect(() => {
7    if (inputRef.current) {
8      inputRef.current.focus()
9    }
10  })
12  return (
13    <div>
14      <input type="text"/>
15      <input type="text"/>
16      <input ref={inputRef} type="text"/>
17      <input type="text"/>
18    </div>
19  )

Again, this is simple if you know the useRef hook. We have 4 inputs in our JSX and let's say we want to focus the third one on the page load. All we need to do is grab a reference to the input that we want to control and call the native function focus() on the current object that useRef provides for us.

These were some very simple examples of useRef hook usage with TypeScript, if you would like me to write more complex TypeScript usage with React.js hooks, let me know in the comments below.

Thank you for reading.

Keep learning and see you in the next one!

Join my newsletter, to receive JavaScript, TypeScript, React.js and more news, tips and other goodies right into your mail box 📥. You can unsubscribe at any time.