Are you tired of feeling like a helpless bystander in your React application? Do you wish you had more control over the DOM nodes that make up your user interface? Well, fear not my friend, because there's a new sheriff in town - useRef
! With this handy tool, you can take the reins and access DOM nodes like never before.
If you're here, chances are you've heard about React Hooks, and probably used some of the famous ones like useState
and useEffect
, but useRef
is new ground for you.
If React were a big bowl of candies, then hooks are the latest additions, very chewy candies with great taste!_ Ohans Emmanuel
In this article, I'll discuss what useRef is, how you can use it, familiar cases you will most often use it, and common pitfalls to avoid. So let's get right into it.
What is useRef?๐ค
I am a big fan of docs, so let's see what React docs say about useRef; "useRef
is a React Hook that lets you reference a value thatโs not needed for rendering". More clearly, it means useRef lets you refer to a value, that is not needed for your component to render or re-render.
Let's break it down further, let's say you have a toy you want to play with, but you only have specific reasons or times you play with that toy. So when you are not playing with it, you store it away, but bring it out later when it is time to play with it again.
useRef
is like a special box for you to put your toys in and a way to remember where exactly you put your toy so you can easily find it when next you need to play with it.useRef
is used in React to help you remember certain things about your application that won't necessarily be needed for rendering. For example, maybe you want to remember what is being typed into a form field, or you want to remember the height of an element on a web page.
How to use it ๐
Like everything in life, there is an instruction manual. The same applies to useRef
, and I will show you how to use it.
The basic way to initialize useRef
is like this:
const myRef = useRef(initialValue)
useRef
returns an object that is mutable with a single property current
.
{current: initialValue}
, current
is set to the initialValue
you passed into the useRef
. You can pass the ref object into as ref
in your React application.
You're probably curious as to why we're not just storing the object in a variable instead. This is because the value stored in your myRef.current
is persisted for the entire lifetime of the component, which means the value does not update even when your component re-renders.
const myRefExample =()=>{
const myRef = useRef("React hooks are beautiful ๐")
// Your ref object will always remain the same after re-renders
// i.e, myRef.current will always be "React hooks are beautiful ๐" even after when your app re-renders
}
If you recall earlier, I said useRef
returns a mutable object, the question is "How do we mutate the value of the current
property?". Let's make some changes to our code above;
const myRefExample =()=>{
const myRef = useRef("React hooks are beautiful ๐")
// to mutate the value of the current property of myRef object we will do
myRef.current = "React hooks are not just beautiful, they make your code looks pretty ๐ค"
//now we've updated the value of the current property of myRef object to a new text. myRef object will now always be {current: "React hooks are not just beautiful, they make your code looks pretty ๐ค"}
}
Familiar use cases of useRef ๐ผ
I am a big fan of learning things by understanding situations and use cases where it has been used before. So I decided to ask a group of my Frontend Engineer friends about situations they've used useRef
and ref
. Here is a list of their responses.
1. "ref
and useRef
for me is used to target the HTML element. I once used it to target an audio element and perform some HTML-specific operations on it like changing the src"
import React, {useRef} from "react"
const AudioPlayer =()=>{
const audioRef = useRef(null);
const playAudio = () => {
audioRef.current.play();
};
const pauseAudio = () => {
audioRef.current.pause();
};
const skipAudio = () => {
audioRef.current.currentTime += 10;
// Skips audio 10 seconds forward
};
return(
<div>
<audio ref={audioRef} src="audio.mp3"></audio>
<button onClick={playAudio}>Play</button>
<button onClick={pauseAudio}>Pause</button>
<button onClick={skipAudio}>Skip 10 Seconds</button>
</div>
)
}
2. "I use it to target dom elements. I mostly use it when I am trying to work on uploading files or images"
import React, { useRef } from 'react';
const FileUpload=()=>{
const fileInputRef = useRef(null);
const handleUpload = () => {
const file = fileInputRef.current.files[0];
console.log(file);
// withe useRef you can now access the current file object
// code to upload the file goes here in case you wanna upload to a server.
};
return (
<div>
<input type="file" ref={fileInputRef} />
<button onClick={handleUpload}>Upload</button>
</div>
);
}
3. "I use it to hold generic value"
import React, { useRef } from 'react';
const Counter =()=> {
// Create two refs using the useRef hook
const countRef = useRef(0);
const messageRef = useRef('');
const handleClick = () => {
// Increment the countRef value
countRef.current++;
// Update the messageRef value based on the current countRef value
if (countRef.current === 1) {
messageRef.current = 'You clicked 1 time';
} else {
messageRef.current = `You clicked ${countRef.current} times`;
}
console.log(messageRef.current);
};
return (
<div>
<p>{messageRef.current}</p>
<button onClick={handleClick}>Click me!</button>
</div>
);
}
export default Counter;
Common pitfalls to avoid when using useRef and ref ๐๐ฟ
Mutating the
ref
object directly: When you create aref
object, you should treat it as a read-only value and avoid mutating it directly. Instead, you should use the.current
property of theref
object to read or update its value.Using
useRef
to force re-renders: AlthoughuseRef
can be used to store values you want to persist between renders, it should not be used as a way to force your component to re-render. For this, it is very much advisable to use hooks likeuseState
oruseReducer
to manage values that affects rendering.Accessing DOM nodes too early with ref: If you try to access a DOM node using a
ref
object before the component that contains it has mounted, theref
will benull
. To avoid this, you should only accessref
objects after the component has mounted.Creating too many
ref
objects: Like the saying that says "Too much of everything is bad", the same applies touseRef
. Although it is very useful too and provides an escape hatch to the DOM for you, creating too manyref
objects however can make your code very ambiguous, and hard to understand and maintain.useRef
should only be used when necessary and should be kept to a minimum. You can read up on how to keep your code easy to understand and less ambiguous here.
Conclusion ๐
I hope this article helps you understand how useRef works and how to apply it in your React applications. Go forth and utilize the power useRef provides in your projects, and remember "With great power comes great responsibility".
Adios! ๐