Website logo

26 Jul 2023

Using
useRef
in
React

When we work on React component, maybe sometimes we need to access DOM element from the website with JavaScript. This is the code that you usually used to access DOM element with plain JavaScript without React.

const sidebarElement = document.querySelector("#sidebar");
const footerElement = document.querySelector("#footer");

Or maybe you want to save an internal value for a component but don't want to have re-render when that value assigned, for example, when we want to have interval for a component. Using useState hook for this case is not good because when value assigned, it will trigger the component to re-render.

const [isPhoneVisible, setIsPhoneVisible] = useState(false);

// This will trigger re-render for the component.
setIsPhoneVisible(true)

It's not good as well if we only use regular variable like let to save a value without re-render. By only using let will not trigger the component to re-render, but if re-render happens from parent component for example, the value will be reset to initial value.

let isPhoneVisible = false;

// Updating the value for this variable will not trigger re-render.
isPhoneVisible = true;

// Suddenly re-render happens in the parent component.
// isPhoneVisible will be reset to initial value, that is false.
// We don't want the value to reset back to initial value.

To overcome those cases, we can use useRef hook. Basically, useRef hook can be used to save value that not need rendering when the value got re-assigned.

const refIsPhoneVisible = useRef(false);

// Change value for useRef not triggering re-render.
refIsPhoneVisible.current = true;

// Suddenly re-render happens in the parent component.
// refIsPhoneVisible still have his value, that is true.

We can also use it to access DOM element like below.

const refSidebarElement = useRef(null);
const refFooterElement = useRef(null);

useEffect(() => {
  refSidebarElement.current?.innerText = "This is Sidebar";
  refFooterElement.current?.innerText = "This is Footer";
}, []);

return (
  <div>
    <div ref={refSidebarElement}>
      <p>Sidebar</p>
    </div>
    <footer ref={refFooterElement}>
      <p>Footer</p>  
    </footer>
  </div>
)

Or maybe we want to use interval in a component.

const refTimer = useRef(null)

useEffect(() => {
  refTimer.current = setInterval(() => {
    console.log("Hello World");
  }, 1000);

  return () => {
    if (refTimer.current) {
      clearInterval(refTimer.current)
    }
  };
}, []);