Last active
December 23, 2021 21:59
-
-
Save trmcnvn/b70dc2bc32455403a3b22a1bea2f4609 to your computer and use it in GitHub Desktop.
Reuse IntersectionObserver's
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function sortObject(object) { | |
Object.keys(object).reduce((prev, curr) => { | |
if (object[curr] !== null && typeof object[curr] === 'object') { | |
prev[curr] = sortObject(object[curr]); | |
return prev; | |
} | |
prev[curr] = object[curr]; | |
return prev; | |
}, {}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { sortObject } from './object'; | |
const ObserverMap = new Map(); | |
const ListenerMap = new WeakMap(); | |
function mapGetWithDefault(map, key, value) { | |
let result = null; | |
if ((result = map.get(key))) { | |
return result; | |
} | |
map.set(key, value); | |
return value; | |
} | |
/** | |
* Returns an existing IntersectionObserver for the matching options, | |
* or creates a new one. | |
* | |
* @param options IntersectionObserver options | |
*/ | |
export default function observerManager(options = {}) { | |
// Get an observer that we have already registered with these options, | |
// or create a new one. | |
const key = JSON.stringify(sortObject(options)); | |
let observer = ObserverMap.get(key); | |
if (observer === undefined) { | |
const callback = entries => { | |
entries.forEach(entry => { | |
const targets = mapGetWithDefault(ListenerMap, entry.target, []); | |
targets.forEach(listener => listener(entry)); | |
}); | |
}; | |
observer = new IntersectionObserver(callback, options); | |
ObserverMap.set(key, observer); | |
} | |
// Observe the target using the correct IntersectionObserver | |
return function observe(target, listener) { | |
const targets = mapGetWithDefault(ListenerMap, target, []); | |
targets.push(listener); | |
observer.observe(target); | |
// Return a function to cleanup | |
return function disconnect() { | |
const idx = targets.indexOf(listener); | |
targets.splice(idx, 1); | |
if (targets.length === 0) { | |
ListenerMap.delete(target); | |
return observer.unobserve && observer.unobserve(target); | |
} | |
}; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment