JAVASCRIPT

Interact with DOM and Store Mutable Values with useRef

Learn to use React's useRef hook for direct DOM manipulation, accessing elements, or storing mutable values that persist across renders without triggering updates.

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

function MyRefComponent() {
  const inputRef = useRef(null);
  const countRef = useRef(0); // For a persistent mutable value
  const [_, setRerender] = useState(0); // To force a re-render for countRef demo

  useEffect(() => {
    // Focus the input field when the component mounts
    if (inputRef.current) {
      inputRef.current.focus();
    }
  }, []); // Empty dependency array means this runs once on mount

  const handleClick = () => {
    // Accessing and manipulating DOM directly
    if (inputRef.current) {
      alert(`Input value: ${inputRef.current.value}`);
      inputRef.current.value = 'Hello useRef!';
    }
  };

  const incrementCountRef = () => {
    countRef.current = countRef.current + 1;
    console.log('countRef.current:', countRef.current);
    // Note: Updating a ref does NOT trigger a re-render.
    // To display the updated value, you'd need a state update.
    setRerender(prev => prev + 1); // Force re-render to display latest countRef.current
  };

  return (
    <div>
      <h2>useRef Example</h2>
      <input type="text" ref={inputRef} placeholder="Focus me on load" />
      <button onClick={handleClick}>Get Input Value & Change</button>

      <h3>Persistent Value with useRef</h3>
      <p>Count Ref Value (does not trigger re-render on its own): {countRef.current}</p>
      <button onClick={incrementCountRef}>Increment Count Ref</button>
      <p>Clicking "Increment Count Ref" updates the ref, but for it to display, a state update (like the dummy state here) is needed to trigger a re-render. `countRef.current` itself is persistent across renders.</p>
    </div>
  );
}

export default MyRefComponent;
How it works: The `useRef` hook returns a mutable ref object whose `.current` property is initialized to the passed argument (`initialValue`). The returned object will persist for the full lifetime of the component. It's commonly used for direct DOM access (e.g., `inputRef.current.focus()`) or to store any mutable value that doesn't need to trigger a re-render when it changes, like a counter that persists across renders (`countRef.current`).

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs