I have here a text animation that is working perfect. What I want to add now is an Intersection Observer so that the animation only starts once I scroll down to the Box.
So what I did to achieve this is: I used the react hook useRef to use as reference to the element I want to observe and applied it to my Box with ref={containerRef}. Then declared a callback function that receives an array of IntersectionObserverEntries as a parameter, inside this function I take the first and only entry and check if it is intersecting with the viewport and if it is then it calls setIsVisible with the value of entry.isIntersecting (true/false). After that I added the react hook useEffect and created an observer contructor using the callback function and the options I just created before. I implemented the logic in a new hook that I called useElementOnscreen.
It is working BUT I am getting a warning and cant solve it:
1. Initial Code tsx file
const useElementOnScreen = <T,>(options: T): [MutableRefObject<HTMLDivElement | null>, boolean] => {
const containerRef = useRef<HTMLDivElement | null>(null);
const [isVisible, setIsVisible] = useState(false);
const callbackFunction = (entries: IntersectionObserverEntry[]) => {
const [entry] = entries;
setIsVisible(entry.isIntersecting);
};
useEffect(() => {
const observer = new IntersectionObserver(callbackFunction, options);
if (containerRef.current) observer.observe(containerRef?.current);
return () => {
if (containerRef.current) observer.unobserve(containerRef?.current);
};
}, [containerRef, options]);
return [containerRef, isVisible];
};
Here I get the warning:
if (containerRef.current) observer.unobserve(containerRef?.current);
The warning is:
(property) MutableRefObject<HTMLDivElement | null>.current: HTMLDivElement
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.
eslint react-hooks/exhaustive-deps
2. What I tried to do to remove the warning is to save the current ref value to a locally scoped variable to be closed over in the function.
const useElementOnScreen = <T,>(options: T): [MutableRefObject<HTMLDivElement | null>, boolean] => {
let observerRefValue: Element | null = null; // <-- variable to hold ref value
const containerRef = useRef<HTMLDivElement | null>(null);
const [isVisible, setIsVisible] = useState(false);
const callbackFunction = (entries: IntersectionObserverEntry[]) => {
const [entry] = entries;
setIsVisible(entry.isIntersecting);
};
useEffect(() => {
const observer = new IntersectionObserver(callbackFunction, options);
if (containerRef.current) observer.observe(containerRef?.current);
observerRefValue = containerRef.current; // <-- save ref value
return () => {
if (observerRefValue) observer.unobserve(observerRefValue); // <-- use saved value
};
}, [containerRef, options]);
return [containerRef, isVisible];
};
But then again here I am getting the warning:
observerRefValue = containerRef.current; // <-- save ref value
(property) MutableRefObject<HTMLDivElement | null>.current: HTMLDivElement | null
Assignments to the 'observerRefValue' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect.eslintreact-hooks/exhaustive-deps
3. Now I changed my let observerRefValue: Element | null = null;
to const [observerRefValue, setObserverRefValue] = useState<Element | null>(null);
And the warning is gone and its working!
However in the current state I am not using setObserverRefValue
anywhere and I am getting the warning 'setObserverRefValue' is assigned a value but never used
.
const useElementOnScreen = <T,>(options: T): [MutableRefObject<HTMLDivElement | null>, boolean] => {
const [observerRefValue, setObserverRefValue] = useState<Element | null>(null);
const containerRef = useRef<HTMLDivElement | null>(null);
const [isVisible, setIsVisible] = useState(false);
const callbackFunction = (entries: IntersectionObserverEntry[]) => {
const [entry] = entries;
setIsVisible(entry.isIntersecting);
};
useEffect(() => {
const observer = new IntersectionObserver(callbackFunction, options);
if (containerRef.current) observer.observe(containerRef?.current);
return () => {
if (observerRefValue) observer.unobserve(observerRefValue); // <-- use saved value
};
}, [observerRefValue, containerRef, options]);
return [containerRef, isVisible];
};
Its just a warning but my question is:
Is my solution correct to handle the previous warning? Or are there maybe better solutions?
And regarding to the'setObserverRefValue' is assigned a value but never used
is there a way to use it in my example so I can get rid of the warning?