While working with React Hooks, I came across useRef and encountered some uncertainty. To address this, I decided to refresh my knowledge and learn more about it.
In this blog article, I will discuss two main concepts and their use cases by providing sample code. These examples are based on the React Documentation, serving as a foundation for illustrating the concepts.
React Documentation
Syntax
import { useRef } from 'react';
const ref = useRef(initialValue);
- An initial value can be of any type.
- It returns an object with a single property: { current: initialValue }.
- The ref.current property is mutable, but it's important not to write or read ref.current during rendering.
1. Referencing a value with a ref
When a variable or state changes in React, it triggers a re-render. However, there are situations where we want to retain the value of a variable without triggering re-renders. This is where useRef
comes in handy as it allows us to store and access such values. Some people often refer to this capability as having a 'box' to store the value.
First, let's see how useRef
works.
import React, { useRef } from "react";
export default function Counter() {
let ref = useRef(0);
const handleClick = () => {
console.log("ref.current", ref.current);
ref.current = ref.current + 1;
};
return (
<>
<button onClick={handleClick}>Click!</button>
<h3>{ref.current}</h3>
</>
)
}
When clicking the button, nothing happens; the value of 0 remains unchanged. However, if you inspect the console, you will notice that the counter is incrementing. In contrast, if you had used useState
, the value of 0 on the browser would change as you click.
Use cases:
When using setInterval
or setTimeout
we get a numerical ID (intervalID or timeoutID). We need to keep this ID when canceling the interval or timeout (clearInterval
or clearTimeout
).
When refreshing the page, we get a new ID again.
The code below is from the React Document.
import React, { useState, useRef } from "react"
export default function Stopwatch() {
const [startTime, setStartTime] = useState(null)
const [now, setNow] = useState(null)
const intervalRef = useRef(null)
function handleStart() {
setStartTime(Date.now())
setNow(Date.now())
clearInterval(intervalRef.current)
intervalRef.current = setInterval(() => {
setNow(Date.now())
}, 10)
}
function handleStop() {
clearInterval(intervalRef.current)
console.log("intervalRef clear", intervalRef.current)
}
let secondsPassed = 0
if (startTime != null && now != null) {
secondsPassed = (now - startTime) / 1000
}
return (
<>
<h1>Time passed: {secondsPassed.toFixed(3)}</h1>
<button onClick={handleStart}>Start</button>
<button onClick={handleStop}>Stop</button>
</>
)
}
2. Manipulating the DOM with a ref
Yes, DOM!
With the use of useRef
, we can accomplish the same thing using useRef
instead of document.getElementById('myInput').focus()
.
const myRef = userRef(null); // { current: null }
<input ref={myRef} />
What these two lines of code do is create a reference to the corresponding DOM node and store it in myRef.current. By doing so, you gain the ability to access this specific DOM node within your event handlers and utilize the browser APIs that are available on it.
Now, this makes sense to me.
myRef.current.style.color = 'red';
Some methods of ref.current
Component methods: play(), pause(), open(), close()
DOM element: focus(), blur(), scrollIntoView()
DOM element: contains()
The contains()
method allows you to check whether a specific DOM element is a descendant of the element associated with the ref. This functionality can be particularly useful for implementing open/close modal behavior.
function myComponent(){
const divRef = useRef(null);
function handleClick(){
if(divRef.current.contains(event.target)){
console.log("Clicked inside the div element or inside the modal.");
} else {
console.log("Clicked outside the div element. You can implement the close-the-modal function here.");
}
};
return (
<div ref={divRef} onClick={handleClick}>
Click inside or outside this dev element.
</div>
)
}
In summary, useRef
offers the ability to store a value without triggering re-renders and facilitates the manipulation of DOM elements, enabling the creation of dynamic functionalities.
Top comments (0)