Home > Net >  react-hooks/exhaustive-deps warning with custom IntersectionObserver hook
react-hooks/exhaustive-deps warning with custom IntersectionObserver hook

Time:07-02

I have this custom react hook copied more of less straight from this dev.to article for use of the IntersecionObserver in React. article here

The Hook

import { useEffect, useRef, useState } from "react"


export const useIntersectionObserver = (options) => {
  const containerRef = useRef(null)
  const [isVisible, setIsVisible] = useState(false)

  const callback = (entries) => {
    const [entry] = entries
    setIsVisible(entry.isIntersecting)
  }


  useEffect(() => {
    let currentEl;

    const observer = new IntersectionObserver(callback, options);

    if (containerRef && containerRef.current) {
      currentEl = containerRef.current;
      observer.observe(currentEl);
    }

    return () => {
      if (containerRef && containerRef.current) {
        currentEl = containerRef.current;
        observer.unobserve(currentEl);
      }
    }
  }, [containerRef, options])

  return [containerRef, isVisible]
}

in my console I have this warning,

The ref value 'containerRef.current' will likely have changed by the time this effect cleanup function runs. If this ref points to a node rendered by React, copy 'containerRef.current' to a variable inside the effect, and use that variable in the cleanup function react-hooks/exhaustive-deps

Can someone please provide a more in-depth explanation as to what exactly this means or point me to a resource? As well as the solution to satisfy the error requirement. From what I can see containerRef.current IS referenced inside the useEffect cleanup, clearly I do not have a solid understanding of what is actually happening here.

CodePudding user response:

The warning exists because, in some cases, the .current value referenced in the body of an effect will be different from the .current value referenced in the cleanup function. In general, if you do

useEffect(() => {
  // code that references someRef.current
  return () => {
    // more code that references someRef.current
  };

you may well be counting on both such references to reference the same value - but that's not guaranteed, and will sometimes be a source of bugs.

In your code, there is only one line in the code which throws the error, which is this one:

return () => {
    if (containerRef && containerRef.current) {
        currentEl = containerRef.current; // <--------
        observer.unobserve(currentEl);
    }
}

Which is reasonable - there's no absolute guarantee that your

  currentEl = containerRef.current;
  observer.observe(currentEl);

in the effect body will be the same element unobserved in the cleanup function.

The fix would be to extract the .current value into a variable in the effect body, and reference that variable in the cleanup.

Also note that a ref will always be truthy - no need to test it.

  useEffect(() => {
    const currentEl = containerRef.current;
    if (!currentEl) return; // no need to attach observer or cleanup

    const observer = new IntersectionObserver(callback, options);
    observer.observe(currentEl);
    return () => {
        observer.unobserve(currentEl);
    };
  }, [containerRef, options])
  • Related