React useRef Hook
The useRef
hook provides a way to directly access and interact with a DOM element or persist a mutable value across renders without causing a re-render. It is particularly useful for scenarios like focusing an input field, accessing DOM elements, or storing references to values that do not trigger a component update.
Let us go through some examples to understand the usage of useRef Hook.
1. Example: Reading Input Value
In this example, we use useRef
to create a reference to an input element. The reference is then used to read the value of the input field and display it when a button is clicked. This demonstrates how useRef
interacts with the DOM without causing re-renders.
App.js
import React, { useRef, useState } from 'react';
function ReadInput() {
const inputRef = useRef(); // Create a reference to the input element
const [inputValue, setInputValue] = useState('');
const readValue = () => {
setInputValue(inputRef.current.value); // Read the input value
};
return (
<div>
<input ref={inputRef} type="text" placeholder="Type something" />
<button onClick={readValue}>Read Input</button>
<p>You entered: {inputValue}</p>
</div>
);
}
export default ReadInput;
Explanation:
useRef
: Creates a reference to the input element, stored ininputRef
.inputRef.current.value
: Reads the current value of the input field.setInputValue
: Updates the state with the input value, which is displayed below the input field.
Output:
2. Example: Storing Mutable Values
Here, useRef
is used to store a mutable value that does not trigger a re-render. We will create a counter that tracks how many times a button is clicked, but the counter will not cause the component to re-render.
App.js
import React, { useRef, useState } from 'react';
function ClickCounter() {
const countRef = useRef(0); // Mutable reference to store the count
const [renderCount, setRenderCount] = useState(0);
const handleClick = () => {
countRef.current += 1; // Increment the reference value
console.log(`Button clicked ${countRef.current} times`);
};
const forceRender = () => {
setRenderCount(renderCount + 1); // Force re-render
};
return (
<div>
<button onClick={handleClick}>Click Me</button>
<button onClick={forceRender}>Force Re-render</button>
<p>Mutable count (does not trigger re-render): {countRef.current}</p>
<p>Render count: {renderCount}</p>
</div>
);
}
export default ClickCounter;
Explanation:
useRef
: Stores a mutable counter value that persists across renders without causing re-renders.countRef.current
: Holds the counter value, which updates without triggering a re-render.- The
forceRender
button demonstrates the difference between updating state and updating a reference.
Output:
3. Example: Tracking Previous State
In this example, useRef
is used to store the previous state of a component. This can be useful when you need to compare the current state with the previous one.
App.js
import React, { useState, useEffect, useRef } from 'react';
function PreviousStateTracker() {
const [value, setValue] = useState('');
const previousValue = useRef('');
useEffect(() => {
previousValue.current = value; // Update the ref with the latest state
}, [value]); // Runs whenever 'value' changes
return (
<div>
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Type something"
/>
<p>Current Value: {value}</p>
<p>Previous Value: {previousValue.current}</p>
</div>
);
}
export default PreviousStateTracker;
Explanation:
useRef
: Stores the previous state value inpreviousValue
.- The
useEffect
hook updates the reference whenever thevalue
state changes. - This approach allows you to track and display the current and previous states without additional re-renders.
Output:
4. Example: Storing a DOM Timer Reference using useRef Hook
This example demonstrates how to use useRef
to store a reference to a DOM timer, allowing you to start and stop the timer without re-creating it on every render.
App.js
import React, { useState, useRef } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
const timerRef = useRef(null);
const startTimer = () => {
if (!timerRef.current) {
timerRef.current = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
}
};
const stopTimer = () => {
clearInterval(timerRef.current);
timerRef.current = null;
};
return (
<div>
<h2>Timer: {seconds} seconds</h2>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
</div>
);
}
export default Timer;
Explanation:
useRef
: Stores the timer ID returned bysetInterval
.startTimer
: Starts the timer and ensures only one timer is active at a time.stopTimer
: Clears the timer and resets the reference tonull
.
Output:
Conclusion
The useRef
hook is a versatile tool in React. Whether you’re interacting with DOM elements, storing mutable values, tracking previous state, or managing external resources like timers, useRef
provides an efficient way to handle these tasks without triggering unnecessary re-renders.