[site/hooks][s]: simplified observer hook
This commit is contained in:
parent
bfb8c52953
commit
fa0775f43a
|
|
@ -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}`, {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue