What are Refs
In the simplest way possible, React refs (which is short for references) are functions that React provides you to reference and interact with DOM nodes and React components directly.[1][2]
Creating Refs
There are two ways to create refs, either use the createRef
method or the useRef
hook.[2]
What’s the difference?
The createRef
method is meant to be used with class components where whereas the useRef
hook is meant to be used with function components.[2]
I don’t use class components so from this point onwards I am going to pretend like the createRef
method does not exist.
Creating Refs Using the useRefs
Hook
As mentioned earlier, you can add refs to your component using the useRef
hook.
// source: https://react.dev/learn/referencing-values-with-refs
import { useRef } from 'react'
// Here a button will increment ref.current on every click
const Counter = () => {
const ref = useRef(0)
const handleClick = () => {
ref.current = ref.current + 1
alert(`You have clicked the button ${ref.current} times.`)
}
return (
<button onClick={handleClick} >
Click Me
</button>
)
}
Note: The
useRef
hook allows you to set an initial value of any type, but this value is ignored after the initial render.[3]
useRef
returns an object with a single property, current
. If you pass an initial value into useRef
, current
will be set to that value, but once the ref object is passed into the ref attribute of a JSX node, whatever initial value set will be overridden by a value set by React. [3]
When to use Refs
Typically, you will use a ref when you need your component to communicate with some external from React, often a browser API that won’t impact the component's appearance. Other possible reasons to use refs are to:
- Store timeout IDs
- Store and manipulate DOM elements
- Store other elements that aren’t necessary to calculate the JSX
If your component needs to store some value, but it does not impact the rendering logic, choose refs.[4]
Best practices for refs
Following these principles will make your components more predictable:
- Treat refs as an escape hatch: In other words, consider refs as a way to access and modify the lower-level behaviour of DOM nodes that React normally abstracts away.[4]
-
Don’t read or write
ref.current
during rendering: If some information is needed during rendering, use state instead because React doesn’t keep track of whenref.current
changes. The only exception to this is code likeif (!ref.current) ref.current = new Thing()
which only sets the ref once during the first render.[4]
Common Use Cases
The following is a list of some of the ways you might use refs in your components.
Focus Control
Programmatically focusing on an input element can be an easy way to improve user experience, cutting out the need for the user to manually drag their cursor over to the input field.
import { useRef, useState, useEffect } from 'react'
const LoginForm = () => {
const ref = useRef(null)
const [email, updateEmail] = useState()
const [password, updatePassword] = useState()
const handleClick = (e, updateValue) => {
...
}
useEffect(() => {
if(ref.current){
ref.current.focus()
}
}, [])
return (
<div>
<h1>Insert a new value</h1>
<form>
<input
placeholder="Email"
ref={ref}
type="text"
onChange={(e) => handleChange(e, updateEmail)}
value={email} />
<input
placeholder="Password"
type="password"
value={password}
onChange={(e) => handleChange(e, updatePassword)} />
<button>Save</button>
</form>
</div>
)
}
The code above works by passing the ref to the email input field. React assigns the input node to ref.current
, which gives lower-level access to the node, which means we can call the focus method on the initial page load to automatically have the email input field focused and ready to receive input.
Link to the sandbox: https://codesandbox.io/p/sandbox/focus-on-render-9l7st4
Triggering Animations
Another common use case for refs is to use them as part of a trigger for some animation on an element. The code example below triggers a slide-in animation on some text when the element enters the viewport.
import React, { useEffect, useRef, useState } from "react";
const App = () => {
const elementRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const node = elementRef.current;
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add(
"animate-in",
"slide-in-from-bottom",
"opacity-100"
);
entry.target.classList.remove("opacity-0");
}
});
});
if (node) {
observer.observe(node);
}
return () => {
if (node) {
observer.unobserve(node);
}
};
}, []);
return (
<>
<div className="h-screen grid place-items-center">
<p className="text-7xl">What it do!</p>
</div>
<div id="animation-section" className="h-screen grid place-items-center">
<p
className="text-7xl slide-in-from-bottom duration-300 delay-100 transition opacity-0"
ref={elementRef}
>
This should slide in from the bottom.
</p>
</div>
</>
);
};
export default App;
Sources:
Top comments (0)