The useRef Hook lets you persist values across renders. It can store mutable values without causing re-renders and can also be used to access a DOM element directly.
Does Not Cause Re-renders
If we used the useState Hook to count the number of renders, we’d end up in an infinite loop because this Hook triggers re-renders. To avoid this, we can use the useRef Hook.
Example:
Use useRef to track the number of application renders.
import { useState , useEffect , useRef } from "react";
import ReactDOM from "react-dom/client";
function App() {
const [inputValue , setInputValue ] = useState("");
const count = useRef(0);
useEffect(() => {
count .current = count .current + 1;
});
return (
<> <input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> <h1>Render Count: {count .current }</h1> </>
); }
const root = ReactDOM .createRoot(document .getElementById('root'));
root .render(<App />);
|
useRef() returns an object with a current property, and you can initialize it with a value like useRef(0).
It’s similar to creating an object like const count = { current: 0 }, where you access the value using count.current.
|
Run this on your computer and type into the input to see the application render count increase.
Accessing DOM Elements
Generally, we let React manage all DOM manipulation. However, useRef can be used in specific cases without causing issues, allowing direct access to an element in the DOM by adding a ref attribute.
Example:
Use useRef to set focus on the input.
import { useRef } from "react";
import ReactDOM from "react-dom/client";
function App() {
const inputElement = useRef();
const focusInput = () => {
inputElement .current .focus();
};
return (
<> <input type="text" ref={inputElement} /> <button onClick={focusInput}>Focus Input</button> </>
); }
const root = ReactDOM .createRoot(document .getElementById('root'));
root .render(<App />);
|
Tracking State Changes
The useRef Hook can also track previous state values by persisting its values between renders.
Example:
Use useRef to track previous state values.
import { useState , useEffect , useRef } from "react";
import ReactDOM from "react-dom/client";
function App() {
const [inputValue , setInputValue ] = useState("");
const previousInputValue = useRef("");
useEffect(() => {
previousInputValue .current = inputValue ;
}, [inputValue ]);
return (
<> <input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> <h2>Current Value: {inputValue }</h2> <h2>Previous Value: {previousInputValue .current }</h2> </>
); }
const root = ReactDOM .createRoot(document .getElementById('root'));
root .render(<App />);
|
This time, we use a combination of useState
, useEffect
, and useRef
to track the previous state. In the useEffect
, we update the useRef
‘s current
value each time the inputValue
changes as text is entered into the input field.