[site/hooks][s]: simplified observer hook

This commit is contained in:
olayway 2022-06-01 16:47:56 +02:00
parent bfb8c52953
commit fa0775f43a
2 changed files with 25 additions and 21 deletions

View File

@ -5,13 +5,10 @@ export const Heading = ({ level, observer }) => (props) => {
useEffect(() => { useEffect(() => {
/* start observing heading's intersection with the bounding box /* start observing heading's intersection with the bounding box
* set by observer's `rootMargin` */ * set by observer's `rootMargin` */
if (observer) { if (!observer) {
observer.observe(document.getElementById(props.id)); return
return () => {
observer.unobserve(document.getElementById(props.id));
}
} }
observer.observe(document.getElementById(props.id));
}); });
return React.createElement(`h${level}`, { return React.createElement(`h${level}`, {

View File

@ -4,28 +4,35 @@ import { useState, useEffect } from 'react';
/* Creates an Intersection Observer to keep track of headings intersecting /* Creates an Intersection Observer to keep track of headings intersecting
* a section of the viewport defined by the rootMargin */ * a section of the viewport defined by the rootMargin */
const getIntersectionObserver = (callback) => { const getIntersectionObserver = (callback) => {
if (typeof window !== 'undefined') { return new IntersectionObserver(
return new IntersectionObserver( (entries) => {
(entries) => { entries.forEach((entry) => {
entries.forEach((entry) => { callback(entry);
callback(entry); });
}); },
}, {
{ root: null,
root: null, rootMargin: "-65px 0% -85% 0%" // 65px is a navbar height
rootMargin: "-65px 0% -85% 0%" // 65px is a navbar height }
} );
);
}
}; };
const useHeadingsObserver = () => { const useHeadingsObserver = () => {
const [activeHeading, setActiveHeading] = useState(""); const [activeHeading, setActiveHeading] = useState("");
const [observer, setObserver] = useState(getIntersectionObserver((entry) => { const [observer, setObserver] = useState(null);
/* Runs only after the first render, in order to preserve the observer
* between component rerenderings (e.g. after activeHeading change). */
useEffect((() => {
const observer = getIntersectionObserver((entry) => {
if (entry.isIntersecting) { if (entry.isIntersecting) {
setActiveHeading(entry.target.id); setActiveHeading(entry.target.id);
} }
})); });
setObserver(observer);
return observer.disconnect();
}), [])
/* On initial render activeHeading will be `null`, since the observer /* On initial render activeHeading will be `null`, since the observer
* has not been instantiated yet. However, we still want to highlight * has not been instantiated yet. However, we still want to highlight