What is useRef?

The useRef is a hook that allows us to persist values across renders without causing a re-render when the value changes. It’s commonly used for two main purposes:

Accessing DOM Elements: We can use useRef to store a reference to a DOM element and directly interact with it (e.g., focusing an input field).

Persisting Mutable Values: We can store values (like flags or previous state) that we want to persist across renders, but without triggering a re-render when they change.
The value we store in useRef is accessible through ref.current.

Syntax:

const myRef = useRef(initialValue);

initialValue: This is the initial value we want to assign to the ref (it can be any data type: object, array, number, etc.).

myRef.current: We access the actual value using .current

A Quick Comparison: useState vs. useRef:

useState: Triggers a re-render when the state value changes.
useRef: Does not trigger a re-render when the value changes.

Code 1 Explanation:

export default function useIsMountedRef() {
  const isMounted = useRef(true);
  useEffect(
    () => () => {
      isMounted.current = false;
    },
    []
  );
  return isMounted;
}

What’s happening here?

useRef(true) initializes isMounted with the value true.
-> isMounted.current = true means the component is mounted when the component first renders.

Inside useEffect, the cleanup function (() => { isMounted.current = false; }) sets isMounted.current to false when the component unmounts (because useEffect with an empty dependency array [] only runs once — after the initial mount and cleanup on unmount).

So, useRef(true) tracks whether the component is mounted:
It starts with true (mounted).
Once the component unmounts, it sets the value to false.

Why use useRef here?

If we’re doing something asynchronous, like an API call, and we want to avoid updating state or doing something after the component has unmounted (because that could lead to errors), we can check if the component is still mounted using this ref.

What is the difference between useRef(true) and useRef(false)?

  • useRef(true) means the component is initially considered “mounted.”
  • useRef(false) would mean the component is initially considered “unmounted,” which could be useful to track something else from the beginning.

Code 2 Explanation:

const mounted = useRef(false);
useEffect(() => {
  if (!mounted.current) {
    mounted.current = true;
  } else {
    // code
  }
}, [dependency]);

What’s happening here?

useRef(false) initializes the mounted ref to false. This is tracking whether the effect has run before.

Inside the useEffect:

  • On the first render, mounted.current is false, so the first block (mounted.current = true) will execute, updating the mounted ref to true.
  • On subsequent renders (or when dependency changes), mounted.current will be true, and it will enter the else block.

Why use useRef here?

This pattern can be useful for skipping certain code on the first render (like an initialization phase) and only running it on subsequent renders.

For example:

  • The first time the component renders, we set mounted.current = true to signal that we’ve seen the component.
  • On subsequent renders (when mounted.current is true), we can run our logic inside the else block.

Summary:

useRef keeps a mutable value across renders, but it doesn’t cause re-renders when that value changes.

In code 1, it tracks whether a component is mounted or not.

In code 2, it tracks whether the effect has already run once, allowing us to skip code on the first render.

Need Help With React Development?

Work with our skilled React developers to accelerate your project and boost its performance.

Hire Reactjs Developers

Support On Demand!

Related Q&A