The useRef
Hook in React allows you to maintain values across renders without causing a re-render when the value changes.
It can be used to store a mutable value and directly access DOM elements.
Avoiding Re-renders
Using the useState
Hook to count application renders can lead to an infinite loop as useState
causes a re-render. Instead, the useRef
Hook can be used to avoid this.
Example
Using useRef
to track application renders:
import { useState, useEffect, useRef } from "react"; import ReactDOM from "react-dom/client"; function Application() { const [text, setText] = useState(""); const renderCount = useRef(0); useEffect(() => { renderCount.current += 1; }); return ( <> <input type="text" value={text} onChange={(e) => setText(e.target.value)} /> <h1>Render Count: {renderCount.current}</h1> </> ); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<Application />);
The useRef
Hook returns an object called current
. When initializing useRef
, you set the initial value: useRef(0)
. It’s similar to: const renderCount = { current: 0 }
. Access the count via renderCount.current
.
Try running this code and typing in the input field to see the application render count increase.
Accessing DOM Elements
React typically handles all DOM manipulation. However, useRef
can be used in specific cases without causing issues.
Add a ref
attribute to an element to access it directly in the DOM.
Example
Using useRef
to focus an input:
import { useRef } from "react"; import ReactDOM from "react-dom/client"; function Application() { const inputRef = useRef(); const focusInputField = () => { inputRef.current.focus(); }; return ( <> <input type="text" ref={inputRef} /> <button onClick={focusInputField}>Focus Input</button> </> ); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<Application />);
Tracking State Changes
The useRef
Hook can also keep track of previous state values since it persists values between renders.
Example
Using useRef
to track previous state values:
import { useState, useEffect, useRef } from "react"; import ReactDOM from "react-dom/client"; function Application() { const [text, setText] = useState(""); const previousText = useRef(""); useEffect(() => { previousText.current = text; }, [text]); return ( <> <input type="text" value={text} onChange={(e) => setText(e.target.value)} /> <h2>Current Value: {text}</h2> <h2>Previous Value: {previousText.current}</h2> </> ); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<Application />);