kakawa/src/hooks/shared-intersection-observer.tsx

78 lines
1.9 KiB
TypeScript
Raw Normal View History

2024-09-27 11:01:36 +05:30
import { useEffect } from 'react';
// eslint-disable-next-line no-unused-vars
type Callback = (entry: IntersectionObserverEntry) => void;
class IntersectionObserverManager {
private observer: IntersectionObserver;
private callbacks: Map<Element, Callback>;
// eslint-disable-next-line no-undef
constructor(options: IntersectionObserverInit) {
this.callbacks = new Map();
this.observer = new IntersectionObserver(this.handleIntersect.bind(this), options);
2024-09-27 11:01:36 +05:30
}
private handleIntersect(entries: IntersectionObserverEntry[]) {
entries.forEach((entry) => {
const callback = this.callbacks.get(entry.target);
if (callback) {
callback(entry);
}
});
}
observe(element: Element, callback: Callback) {
if (element && callback) {
this.callbacks.set(element, callback);
this.observer.observe(element);
}
}
unobserve(element: Element) {
if (element) {
this.callbacks.delete(element);
this.observer.unobserve(element);
}
}
disconnect() {
this.observer.disconnect();
this.callbacks.clear();
}
}
let manager: IntersectionObserverManager | null = null;
// eslint-disable-next-line no-undef
const getObserverManager = (options: IntersectionObserverInit) => {
if (!manager) {
manager = new IntersectionObserverManager(options);
}
return manager;
};
export const useSharedIntersectionObserver = (
// eslint-disable-next-line no-undef
options: IntersectionObserverInit,
) => {
useEffect(() => {
return () => {
// Cleanup logic if needed
// For example, disconnect the observer when the component unmounts entirely
// This depends on your application's lifecycle
};
}, []);
if (typeof window === 'undefined') {
// Return a dummy manager for SSR
return {
observe: () => {},
unobserve: () => {},
disconnect: () => {},
} as unknown as IntersectionObserverManager;
}
return getObserverManager(options);
};