Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Understanding useRef: DOM Access in React

Understanding useRef

~10 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

useRef has two very different but equally important use cases: getting direct access to a real DOM element, and "remembering" a value across multiple render passes WITHOUT that triggering a re-render (unlike useState).

Use case 1: direct access to a DOM element

Normally in React you only describe WHAT the interface should look like, and never touch the actual DOM manually. Sometimes, though, you do need direct access – for example, to automatically focus an input field as soon as the page loads. That's what useRef is for:

import { useRef, useEffect } from 'react';

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

  useEffect(() => {
    inputRef.current.focus(); // real DOM element, directly addressable
  }, []);

  return <input ref={inputRef} type="text" />;
}

useRef(null) creates an object with exactly one property: current, initially null. When the same object is passed as the ref prop to a JSX element, React automatically fills inputRef.current with the real DOM node once it exists – from then on, you can call regular DOM methods like .focus(), .scrollIntoView(), or .value on it.

Extending App.jsx: an auto-focused search field

Let's build this directly into our project – a search field that filters the product list AND gets focused automatically on load. Replace src/App.jsx:

src/App.jsx
import { useEffect, useRef, useState } from 'react';
import ProductCard from './components/ProductCard';

const SAMPLE_PRODUCTS = [
  { sku: 'boots-01', name: 'Hiking Boots', price: 89.99, imageUrl: 'https://picsum.photos/seed/1/300' },
  { sku: 'backpack-01', name: 'Trekking Backpack', price: 59.5, imageUrl: 'https://picsum.photos/seed/2/300' },
  { sku: 'jacket-01', name: 'Rain Jacket', price: 74.0, imageUrl: 'https://picsum.photos/seed/3/300' },
];

function App() {
  const [query, setQuery] = useState('');
  const searchInputRef = useRef(null);

  useEffect(() => {
    document.title = `Product Catalog (${SAMPLE_PRODUCTS.length} products)`;
    searchInputRef.current.focus();
  }, []);

  const filtered = SAMPLE_PRODUCTS.filter((product) =>
    product.name.toLowerCase().includes(query.toLowerCase())
  );

  return (
    <div className="app">
      <h1>Product Catalog</h1>
      <input
        ref={searchInputRef}
        type="text"
        placeholder="Search products..."
        value={query}
        onChange={(event) => setQuery(event.target.value)}
      />
      <div className="product-grid">
        {filtered.map((product) => (
          <ProductCard
            key={product.sku}
            name={product.name}
            price={product.price}
            imageUrl={product.imageUrl}
            onSelect={() => alert(product.name + ' tapped')}
          />
        ))}
      </div>
    </div>
  );
}

export default App;

value={{query}} + onChange={{(event) => setQuery(event.target.value)}} is what's called a "controlled" input field – the VALUE comes from React state (useState), while ref additionally gives access to the REAL DOM element to call .focus(). Both concepts don't conflict, they solve different problems – more on controlled fields in chapter 13.

Use case 2: remembering values without re-rendering

The second, less obvious use case: useRef can also serve as a "container" for any mutable value that persists across render passes – unlike useState, though, changing ref.current does NOT trigger a re-render:

function ClickCounter() {
  const clickCountRef = useRef(0);

  function handleClick() {
    clickCountRef.current = clickCountRef.current + 1;
    console.log('Clicked so far:', clickCountRef.current);
    // No re-render! The display would NOT update,
    // even if we showed {clickCountRef.current} in the JSX.
  }

  return <button onClick={handleClick}>Click me</button>;
}

Achtung: This is EXACTLY why useRef is the wrong choice when a changed value should actually become visible on screen – that's what useState is for. Use useRef for values that should run "in the background" (timer IDs, previous values for comparison, DOM elements), but that are never directly displayed in JSX.