| Feature | useState() | useRef() |
|---|---|---|
| Causes Re-render | ✅ Yes | ❌ No |
| Stores Data | ✅ Yes | ✅ Yes |
| UI Updates Automatically | ✅ Yes | ❌ No |
| Used For | State Management | DOM Access & Persistent Values |
| Value Access | Direct variable | .current property |
| Re-render Performance | More renders | Better for non-UI data |
useState()
Used when data affects the UI.
Example
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<>
<h2>{count}</h2>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</>
);
}
What Happens?
Click Button
↓
setCount()
↓
State Changes
↓
Component Re-renders
↓
UI Updates
useRef()
Stores data without re-rendering the component.
Example
import { useRef } from "react";
function Counter() {
const countRef = useRef(0);
const increment = () => {
countRef.current++;
console.log(countRef.current);
};
return (
<button onClick={increment}>
Increment
</button>
);
}
What Happens?
Click Button
↓
countRef.current++
↓
Value Changes
↓
NO Re-render
The UI will not update automatically.
Example Showing the Difference
import { useState, useRef } from "react";
function App() {
const [count, setCount] = useState(0);
const refCount = useRef(0);
return (
<>
<h2>State: {count}</h2>
<h2>Ref: {refCount.current}</h2>
<button
onClick={() => setCount(count + 1)}
>
State Update
</button>
<button
onClick={() => refCount.current++}
>
Ref Update
</button>
</>
);
}
Result
State button:
State: 1
Ref: 0
UI updates immediately.
Ref button:
State: 1
Ref: 0
UI does not change because no re-render occurred.
Common Use Case 1: Access DOM Element
import { useRef } from "react";
function Login() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>
Focus
</button>
</>
);
}
Used for:
- Focus input
- Scroll element
- Video controls
- Direct DOM access
Common Use Case 2: Store Previous Value
import { useEffect, useRef, useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const previousCount = useRef();
useEffect(() => {
previousCount.current = count;
});
return (
<>
Current: {count}
Previous: {previousCount.current}
</>
);
}
Common Use Case 3: Store Timer ID
const timerRef = useRef();
timerRef.current = setInterval(() => {
console.log("Running");
}, 1000);
Avoids unnecessary re-renders.
Easy Way to Remember
useState
const [name, setName] = useState("");
When value changes:
Re-render Component
Use when UI should change.
useRef
const nameRef = useRef("");
When value changes:
No Re-render
Use when UI does not need to change.
Interview Answer
useState()is used to manage component state and triggers a re-render whenever the state changes.useRef()is used to store mutable values or access DOM elements without causing a re-render. I useuseState()for data that affects the UI, such as form fields and counters, anduseRef()for DOM manipulation, storing previous values, timer IDs, or any data that should persist across renders without updating the UI.
