Skip to content

Instantly share code, notes, and snippets.

@hkjpotato
Last active April 28, 2020 23:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hkjpotato/43b1e53789030883e4ba82cccf873112 to your computer and use it in GitHub Desktop.
Save hkjpotato/43b1e53789030883e4ba82cccf873112 to your computer and use it in GitHub Desktop.
why react-intersection-observer is made in that way?
/**
my naive hook
- in the hook itself I always instantiate an observer instance, otherwise I dont know where to hold it
- also I pass in a sepefic callback used just for the current comp
- the callback detects if is intersecting, if so call a function right in side the component scope, and also unobserve if trigger only once
I do this because I feel like everything is local, and can only be assessed locally
Why I think each item needs its own observer? Because to instantiate an observer I need to pass in a callback. This callback
must be defined during the instantiation. However, at that momement I dont even know which items to be observed.
Even if I know the children when instantiate it (like putting at a parent comp's componentDidMount and use some selector to
collect the dom, I feel like the nested layers betweeen parent child might make the update unclear.
Overall, my mind is limited by the 'scope'.
Class, function can create scope..but dont forget the js module file itself is a native scope.
Use it smartly to hold references of sharable objects.
*/
function useNaiveInView(triggerOnce) {
const ref = useRef();
const [inView, setInView] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setInView(true); // in the scope
if (triggerOnce) {
observer.unobserve(ref.current);
}
}
});
});
observer.observe(ref.current);
}, []);
return [ref, inView];
}
/**
* this guy has extract that concern of scope
* he writes a generic callback
* which does not rely on local scope but a file(module) scope
*
*/
let observer = null;
const instances = new Map();
// observe is like a setter to access this internal state
function observe(ele, callback) {
if (!observer) {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
// if (entry.isIntersecting)
// let inView = entry.isIntersecting;
// instance.callback
if (entry.isIntersecting) {
const instance = instances.get(entry.target);
instance.callback(true);
}
})
});
}
const instance = {
callback: callback,
};
instances.set(ele, instance);
observer.observe(ele);
}
function destroy() {
observer.disconnect();
instances.clear();
}
function unobserve(ele) {
observer.unobserve(ele);
instances.delete(ele);
if (instances.size === 0) {
observer.disconnect();
}
}
function useInView(triggerOnce) {
const [inView, setInview] = useState(false);
const setRef = useCallback((node) => {
// https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
if(node) {
observe(node, (inView) => {
setInview(inView)
if (triggerOnce) {
unobserve(node)
}
})
}
},[]);
return [setRef, inView];
}
//https://gist.github.com/thebuilder/fb07c989093d4a82811625de361884e7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment