Using document.querySelector instead of useRef in React

Loading

Why This Is Problematic

Using document.querySelector in React components is generally considered an anti-pattern because:

  1. Breaks React’s Virtual DOM abstraction – Direct DOM manipulation bypasses React’s reconciliation process
  2. Causes synchronization issues – Selected elements might not match React’s rendered output
  3. Leads to fragile selectors – Relies on class/ID naming that might change
  4. Performance overhead – DOM queries are more expensive than refs
  5. SSR incompatibility – Will fail during server-side rendering

When useRef Is the Better Choice

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

  useEffect(() => {
    // Access the DOM element safely
    if (inputRef.current) {
      inputRef.current.focus();
    }
  }, []);

  return <input ref={inputRef} />;
}

Proper Ref Usage Patterns

  1. Accessing DOM elements:
   const buttonRef = useRef(null);
   <button ref={buttonRef}>Click</button>
  1. Managing focus:
   useEffect(() => {
     inputRef.current?.focus();
   }, []);
  1. Measuring elements:
   useEffect(() => {
     const width = divRef.current?.clientWidth;
   }, []);

When You Might Still Need querySelector

  1. Accessing elements outside your component (modals, portals)
  2. Working with third-party libraries that require DOM nodes
  3. Selecting elements you don’t control

Best Practices

  1. Always prefer useRef for elements you render
  2. Use ref callbacks for dynamic refs:
   <div ref={(el) => { if (el) /* do something */ }} />
  1. Combine with useEffect for safe access
  2. Consider custom hooks for common ref patterns:
   function useFocus() {
     const ref = useRef(null);
     useEffect(() => ref.current?.focus(), []);
     return ref;
   }

Performance Comparison

ApproachPerformance ImpactReact CompatibilitySSR Safe
useRefLowFullYes
querySelectorHighPartialNo

Leave a Reply

Your email address will not be published. Required fields are marked *