Mastering DOM Access in React: Trading querySelector for useRef

In this blog post, we'll delve into why you should use useRef in React applications instead of document.querySelector.

Both methods provide a way to access DOM nodes directly, but useRef is the preferred way in React for a few reasons.

Understanding useRef and document.querySelector

First, let's briefly describe what these two methods do:

  • document.querySelector: This is a method provided by the browser's Document Object Model (DOM) API. It returns the first Element within the document that matches the specified selector, or group of selectors.
  • useRef: This is a Hook in React that returns a mutable ref object whose .current property is initialized with the passed argument. The returned object will persist for the full lifetime of the component.

Why useRef Is Preferred in React

Here are a few reasons why useRef is generally better to use than document.querySelector in React applications:

  • Component isolation: useRef adheres to React’s component-based architecture and does not affect other components, whereas document.querySelector affects the entire document. This can lead to unexpected behavior if multiple components are trying to manipulate the same DOM element.
  • Performance: useRef accesses the node reference directly and is more performant than document.querySelector, which has to traverse the DOM tree to find the element.
  • Integration with React's rendering cycle: When you use useRef, you're working with React's rendering cycle, not against it. This means that your code will be more aligned with React's best practices and more likely to work correctly in a variety of situations.

Examples

Here's an example of how to use document.querySelector and useRef to access a DOM node.

Using document.querySelector:


import React, { useEffect } from "react";

function App() {
 useEffect(() => {
    const button = document.querySelector("#myButton");
    button.addEventListener("click", () => {
    console.log("Button clicked!");
    });
}, []);

return <button id="myButton">Click me</button>
}

export default App;
        

Using useRef:


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

function App() {
    const buttonRef = useRef(null);

    useEffect(() => {
    const button = buttonRef.current;
    button.addEventListener("click", () => {
        console.log("Button clicked!");
    });
    }, []);

    return <button ref={buttonRef}>Click me</button>;
 }

export default App;
        

In the first example, we use document.querySelector to select the button element. This can work, but it's not the ideal way to do it in a React application.

In the second example, we use useRef to get a reference to the button element. We then use this reference to add an event listener to the button. This way, we're working with React's rendering cycle and not against it, which can lead to more predictable behavior and better performance.

Conclusion

While document.querySelector can be used in a React application, it's generally better to use useRef to access DOM nodes directly. useRef adheres more closely to React's component-based architecture, is more performant, and integrates better with React's rendering cycle.

It's an essential tool in any React developer's toolkit and can help you write more efficient and effective React code.