In React development, managing references to DOM elements or preserving mutable values across renders is often necessary. This is where theuseRefhook becomes an essential tool. Introduced with React Hooks in version 16.8,useRefprovides a simple and powerful way to work with DOM nodes directly or hold values that persist without triggering re-renders. Whether you’re focusing an input, controlling animations, or storing a timer ID, understandinguseRefis vital for writing clean and effective functional components.
What is the useRef Hook?
TheuseRefhook is a built-in React hook that allows you to create a mutable reference object. This reference is preserved across re-renders and does not cause the component to re-render when its value changes. It’s commonly used for accessing or modifying DOM elements directly and storing mutable data that doesn’t need to trigger UI updates.
Basic Syntax
const myRef = useRef(initialValue);
The object returned byuseRefhas acurrentproperty that holds the actual value:
myRef.current
Using useRef to Access DOM Elements
One of the most frequent use cases ofuseRefis accessing DOM nodes directly. This is useful when you need to perform actions like focusing an input field, controlling scroll position, or interacting with third-party libraries.
Example: Focusing an Input
import React, { useRef } from 'react'; function FocusInput() { const inputRef = useRef(null); const handleClick = () =>{ inputRef.current.focus(); }; return ( <div> <input ref={inputRef} type='text' /> <button onClick={handleClick}>Focus Input</button> </div> ); }
In this example,inputRefholds a reference to the input element, allowing the button to callfocus()on it when clicked.
Storing Mutable Values with useRef
UnlikeuseState, changing auseRefvalue does not trigger a re-render. This makes it ideal for storing values that you want to preserve between renders without affecting the UI.
Example: Tracking Render Count
import React, { useRef, useEffect, useState } from 'react'; function RenderCounter() { const count = useRef(0); const [value, setValue] = useState(0); useEffect(() =>{ count.current += 1; }); return ( <div> <p>Render count: {count.current}</p> <button onClick={() =>setValue(value + 1)}>Re-render</button> </div> ); }
Here,count.currentincreases on each render, but changing its value doesn’t cause a re-render. Only theuseStatehook triggers updates to the component.
Difference Between useRef and useState
Although bothuseRefanduseStatestore values, they behave differently in important ways:
- useRef: Mutating
currentdoes not trigger a re-render - useState: Updating state causes the component to re-render
- useRef: Primarily for referencing DOM elements or persisting data across renders silently
- useState: Best for managing dynamic UI data
Using useRef in Event Handlers
useRefis also useful for referencing values within callbacks without worrying about closures or stale data. It allows you to track the latest value of a variable inside an event listener without re-declaring the handler.
Example: Tracking Latest Value
function TimerComponent() { const intervalId = useRef(null); const startTimer = () =>{ intervalId.current = setInterval(() =>{ console.log('Running...'); }, 1000); }; const stopTimer = () =>{ clearInterval(intervalId.current); }; return ( <div> <button onClick={startTimer}>Start</button> <button onClick={stopTimer}>Stop</button> </div> ); }
WithintervalIdstored inuseRef, both functions can access the same interval reference, making the logic clean and reliable.
Common useRef Use Cases
- Accessing DOM nodes (inputs, divs, etc.)
- Storing timer IDs (e.g.,
setTimeout,setInterval) - Preventing unnecessary re-renders with persisted values
- Tracking previous props or state
- Integrating with third-party DOM libraries or APIs
Tracking Previous State with useRef
function PreviousValueExample({ value }) { const previousValue = useRef(); useEffect(() =>{ previousValue.current = value; }, [value]); return ( <p>Previous: {previousValue.current}, Current: {value}</p> ); }
This pattern allows you to compare the previous and current values of a prop without triggering additional renders.
Things to Keep in Mind
- Don’t rely on
useReffor triggering UI updates useuseStatefor that - Changing
ref.currentdoes not notify React React won’t know something changed unless you manage it explicitly - Refs are best for storing data that should survive re-renders without affecting rendering logic
- When accessing DOM nodes, ensure the ref is attached to a valid element
TheuseRefhook is a versatile and powerful feature in React that serves multiple purposes, from accessing DOM elements to storing values across renders without causing re-renders. By understanding how to useuseRefeffectively, developers can optimize performance, simplify event handling, and manage non-UI logic within their components. Whether you are building forms, timers, animations, or working with third-party libraries, masteringuseRefis a fundamental step in becoming a proficient React developer.