React useRef Hook: Manage DOM and Persistent Values Without Re-Renders

Last updated 2 months, 2 weeks ago | 81 views 75     5

Tags:- React

Introduction: Why useRef Matters in React

React’s rendering system is powerful, but sometimes, you need to store values that don’t trigger re-renders—like tracking a timer ID or referencing a DOM element. That’s where the useRef Hook shines.

The useRef Hook is often overlooked but extremely handy for scenarios where:

  • You need to directly interact with a DOM element.

  • You want to persist values between renders without causing a re-render.

  • You need to avoid using useState for non-UI-related values.

Think of useRef as a box that holds a mutable value. You can change the value inside without causing your component to re-render.


Understanding useRef (Step-by-Step)

1. Basic Syntax

const myRef = useRef(initialValue);
  • The .current property holds the mutable value.

  • Unlike state, updating .current doesn’t trigger a re-render.


2. Accessing DOM Elements

You can use useRef to reference a DOM node, similar to document.getElementById.

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

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

  useEffect(() => {
    inputRef.current.focus(); // Focus the input on mount
  }, []);

  return <input ref={inputRef} placeholder="Type here..." />;
}

3. Storing Mutable Values

useRef can store any value that persists across renders but doesn’t affect the UI.

function TimerTracker() {
  const count = useRef(0);

  const handleClick = () => {
    count.current++;
    console.log(`Clicked ${count.current} times`);
  };

  return <button onClick={handleClick}>Click Me</button>;
}
  • Note: This will not re-render the component when count.current changes.


4. Avoiding Unnecessary Re-Renders

If you store frequent updates in useState, it causes re-renders. useRef avoids that.

Comparison Table: useRef vs useState

Feature useRef useState
Triggers re-render ❌ No ✅ Yes
Persists across renders ✅ Yes ✅ Yes
Stores DOM refs ✅ Yes ❌ No
Best use case Timer ID, DOM access, caches UI state, form values, etc.

Complete Working Example: Form Focus & Timer Tracker

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

function App() {
  const inputRef = useRef(null);
  const timerRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus(); // Autofocus input on mount

    timerRef.current = setInterval(() => {
      console.log('Timer running...');
    }, 1000);

    return () => {
      clearInterval(timerRef.current); // Cleanup on unmount
    };
  }, []);

  const handleClick = () => {
    alert(`Current input value: ${inputRef.current.value}`);
  };

  return (
    <div style={{ padding: '20px' }}>
      <input ref={inputRef} placeholder="Enter something..." />
      <button onClick={handleClick} style={{ marginLeft: '10px' }}>
        Show Input
      </button>
    </div>
  );
}

export default App;

Tips & Common Pitfalls

Best Practices

  • Use useRef for DOM manipulation or storing non-UI values.

  • Name your refs clearly (inputRef, timerRef) for readability.

  • Clean up timers or subscriptions inside useEffect.

⚠️ Common Mistakes

  • Expecting re-renders: Changing .current won’t re-render the component.

  • Accessing .current before mount: Always check if it's null when dealing with DOM refs.

  • Overusing refs: Don’t use them for everything—state is still the right tool for UI-driven logic.


When to Use useRef vs Other Hooks

Scenario Recommended Hook
Accessing DOM elements useRef
Storing interval/timer IDs useRef
Persisting non-UI data useRef
UI-driven data (triggers re-render) useState
Sharing logic between components useContext

Conclusion: Master useRef for Clean, Efficient React Code

The useRef Hook is your best friend for dealing with:

  • Direct DOM interactions

  • Persistent mutable values

  • Avoiding performance hits from re-renders

Keep in mind: If your value doesn't affect the UI directly and doesn't need to trigger a render—useRef is likely what you need.


Actionable Takeaways

  • Use useRef to focus inputs or access other DOM nodes.

  • Store mutable values like counters, timers, or cache references.

  • Avoid overusing state for non-visual logic—useRef is more performant.

  • Combine useRef with useEffect for timed or delayed logic.