Skillversitas

useRef Hook

What Is a Ref?

useRef returns a mutable object with a .current property. This object persists across the entire component lifecycle without causing a re-render when changed.

useRef for DOM Access

import React, { useRef, useEffect } from 'react';

function TextInput() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

useRef as a Mutable Container

useRef can store any value that persists between renders without triggering a re-render.

function Stopwatch() {
  const [time, setTime] = React.useState(0);
  const intervalRef = useRef(null);

  const start = () => {
    intervalRef.current = setInterval(() => {
      setTime(prev => prev + 1);
    }, 1000);
  };

  const stop = () => {
    clearInterval(intervalRef.current);
  };

  React.useEffect(() => {
    return () => clearInterval(intervalRef.current);
  }, []);

  return (
    <div>
      <p>{time}</p>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </div>
  );
}

Differences Between useRef and useState

Aspect useState useRef
Re-renders on update Yes No
DOM access Not direct Direct
Value type Primitive/state Mutable object
Persists across renders Yes Yes
function Comparison() {
  const [count, setCount] = React.useState(0);
  const countRef = useRef(0);

  const handleState = () => setCount(count + 1); // Re-renders
  const handleRef = () => { countRef.current += 1; }; // No re-render

  return (
    <div>
      <p>State: {count}</p>
      <p>Ref: {countRef.current}</p>
      <button onClick={handleState}>State + 1</button>
      <button onClick={handleRef}>Ref + 1</button>
    </div>
  );
}

Example: Input Focus

function SearchForm() {
  const searchRef = useRef(null);

  useEffect(() => {
    searchRef.current.focus();
  }, []);

  const handleSubmit = (e) => {
    e.preventDefault();
    alert(`Searching: ${searchRef.current.value}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input ref={searchRef} type="search" placeholder="Search..." />
      <button type="submit">Search</button>
    </form>
  );
}

Scrolling to an Element

function CommentSection() {
  const bottomRef = useRef(null);
  const [comments, setComments] = React.useState([]);

  const addComment = (text) => {
    setComments(prev => [...prev, text]);
    // Scroll to the newest comment
    setTimeout(() => {
      bottomRef.current.scrollIntoView({ behavior: 'smooth' });
    }, 100);
  };

  return (
    <div>
      {comments.map((c, i) => (
        <p key={i}>{c}</p>
      ))}
      <div ref={bottomRef} />
      <button onClick={() => addComment('New comment')}>Add</button>
    </div>
  );
}

useRef is useful for DOM access and for values that do not need to trigger a render. Next we will study useCallback and useMemo for performance optimization.