19 Feb 2024
useRef hook in React provides a way to persist values across renders without causing re-renders when the value changes. It primarily serves two purposes: accessing and persisting references to DOM elements and storing mutable values that persist between renders without causing re-renders.
Explanation of the useRef hook:
Purpose:
- DOM references:
useRefallows you to reference DOM elements directly within functional components without relying ondocument.getElementByIdor similar methods. - Holding mutable values:
useRefcan hold values that persist between renders without causing the component to re-render when the value changes. This is useful for storing mutable values that do not need to trigger re-renders.
Syntax:
const myRef = useRef(initialValue);
myRef: The object returned byuseRefholds acurrentproperty that can be used to access the current value of the reference.initialValue: Optional. It initializes thecurrentproperty of the reference. The value provided asinitialValueis not used for re-renders.
When to Use:
- Accessing DOM elements: When you need to access or manipulate a DOM element imperatively.
- Holding mutable values: When you need to store values that persist between renders without causing re-renders.
Accessing DOM Elements:
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const inputRef = useRef(null);
useEffect(() => {
// Focus the input element on mount
inputRef.current.focus();
}, []);
return (
<div>
<input type="text" ref={inputRef} />
</div>
);
}
In this example, useRef is used to create a reference to the input element. This reference can be accessed using inputRef.current, allowing you to imperatively call methods like focus() on the input element.
Holding Mutable Values:
import React, { useRef, useState } from 'react';
function MyComponent() {
const counterRef = useRef(0);
const [renderCount, setRenderCount] = useState(0);
const incrementCounter = () => {
counterRef.current++;
setRenderCount(renderCount + 1); // Triggers re-render
};
return (
<div>
<p>Counter: {counterRef.current}</p>
<p>Render Count: {renderCount}</p>
<button onClick={incrementCounter}>Increment Counter</button>
</div>
);
}
In this example, useRef is used to hold a mutable value (counterRef.current). Whenever incrementCounter is called, the value of counterRef.current is incremented without triggering a re-render. Meanwhile, renderCount is stored in the component's state and does trigger a re-render when updated.
Common Patterns:
- Accessing child components:
useRefcan be used to access methods or properties of child components. - Storing previous values: You can use
useRefto store and access previous values of state or props to perform comparisons or calculations. - Caching values:
useRefcan be used to cache values computed during render to avoid recomputation on subsequent renders.
⚠️ Cautions:
- Mutable values: Be cautious when using mutable values stored in
useRef, especially if they are expected to cause side effects. - Synchronization: Changes to
useRefvalues do not trigger re-renders. You need to manage updates to the component's state separately if you want to trigger re-renders based on changes touseRefvalues.
Key Points of useRef:
-
Creating a Ref Object: When you call
useRef, it returns a mutable ref object with a.currentproperty initialized to theinitialValueprovided. This ref object persists for the entire lifecycle of the component. -
Mutable Ref Object: The
.currentproperty of the ref object is mutable, meaning you can change its value directly without causing a re-render of the component. -
Accessing DOM Nodes: One common use case for
useRefis to access DOM nodes directly. You can attach the ref object to a JSX element using therefattribute, and then access the DOM node using the.currentproperty.import React, { useRef, useEffect } from 'react'; function MyComponent() { const inputRef = useRef(null); useEffect(() => { inputRef.current.focus(); }, []); return <input ref={inputRef} />; } -
Preserving Values Between Renders: Another use case for
useRefis to preserve values between renders without causing re-renders. Since changing the.currentproperty of the ref object doesn't trigger a re-render, you can useuseRefto store values that you want to persist across renders without affecting the rendering of the component.import React, { useRef } from 'react'; function MyComponent() { const renderCount = useRef(0); renderCount.current++; return <div>Render count: {renderCount.current}</div>; } -
Imperative DOM Manipulation:
useRefis useful for imperative DOM manipulation or any situation where you need to store mutable state that doesn't trigger a re-render.