Skip to content

Instantly share code, notes, and snippets.

@timc1
Last active May 25, 2022 13:36
Show Gist options
  • Save timc1/00786d279b9b3e4d2c3a579fcb5ec655 to your computer and use it in GitHub Desktop.
Save timc1/00786d279b9b3e4d2c3a579fcb5ec655 to your computer and use it in GitHub Desktop.
very fast rendering of large lists, without windowing/virtualization
import { useIsomorphicEffect } from "@hooks/useIsomorphicEffect";
import React from "react";
const cache: Map<string, { height: number }> = new Map();
/**
* Very fast rendering of large lists, without windowing/virtualization
*
* Wrap any list item with `<Item><MyListItem /></Item` and we
* will ensure that only what appears within the viewport is what
* is rendered.
*/
export function Item({
id,
children,
...rest
}: {
id: string;
children: React.ReactNode;
}) {
const [height, setHeight] = React.useState(cache.get(id)?.height ?? 0);
const [visible, setVisible] = React.useState(() => {
if (typeof window !== "undefined") {
if (cache.get(id)?.height) {
return false;
}
}
return true;
});
const ioRef = React.useRef<IntersectionObserver | null>(null);
const elRef = React.useRef<HTMLElement | null>(null);
const refSetter = React.useCallback((el) => {
const io = ioRef.current;
if (io !== null && elRef.current !== null) {
io.unobserve(elRef.current);
}
elRef.current = el;
if (io !== null && elRef.current !== null) {
io.observe(elRef.current);
}
}, []);
useIsomorphicEffect(() => {
const update = (entries: any) => {
for (let entry of entries) {
if (entry.isIntersecting) {
setVisible(true);
} else {
const { height } = entry.target.getBoundingClientRect();
cache.set(id, { height });
setVisible(false);
setHeight(height);
}
}
};
const io = ioRef.current ? ioRef.current : new IntersectionObserver(update);
const el = elRef.current;
if (el !== null) {
io.observe(el);
}
ioRef.current = io;
return () => {
io.disconnect();
};
}, [id]);
const style = React.useMemo(() => (visible ? {} : { height }), [visible, height]);
return (
<div ref={refSetter} {...rest} style={style}>
{children}
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment