React JS

Difference Between useState() and useRef()

FeatureuseState()useRef()
Causes Re-render✅ Yes❌ No
Stores Data✅ Yes✅ Yes
UI Updates Automatically✅ Yes❌ No
Used ForState ManagementDOM Access & Persistent Values
Value AccessDirect variable.current property
Re-render PerformanceMore rendersBetter 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 use useState() for data that affects the UI, such as form fields and counters, and useRef() for DOM manipulation, storing previous values, timer IDs, or any data that should persist across renders without updating the UI.