Skip to content

Instantly share code, notes, and snippets.

@leolabs
Last active June 16, 2020 10:55
Show Gist options
  • Save leolabs/eabf1c0807950f38a87fb92b4d7ca6ef to your computer and use it in GitHub Desktop.
Save leolabs/eabf1c0807950f38a87fb92b4d7ca6ef to your computer and use it in GitHub Desktop.
Increasing performance of long lists in React using IntersectionObservers

Increasing performance of long lists in React using IntersectionObservers

This component provides a simple way to improve render performance of long lists in React. It's a simple alternative to solutions like react-window that still works well with animation libraries like react-spring or framer-motion.

Example usage:

const List = ({ items }) => (
  <div>
    {items.map((item, index) => (
      <WindowedRow height={64} index={index}>
        <Content item={item} />
      </WindowedRow>
    ))}
  </div>
);
import React, { useEffect, useRef, useState } from 'react';
interface Props {
/**
* Shows the row on the initial render. This should be set to true
* for rows that are likely to be in the viewport initially.
*/
initiallyVisible?: boolean;
index: number;
height: number;
}
/**
* This component displays a row but only mounts its contents when
* it's in the viewport. This is done using an IntersectionObserver.
*/
export const WindowedRow: React.FC<Props> = ({
initiallyVisible,
index,
height,
children,
}) => {
const [inView, setInView] = useState<boolean>(
initiallyVisible ?? index * height < window.innerHeight
);
const wrapper = useRef<HTMLDivElement>(null);
const intersectionObserver = useRef<IntersectionObserver>(
new IntersectionObserver(entries => {
const entry = entries[0];
setInView(entry?.isIntersecting);
})
);
useEffect(() => {
const observer = intersectionObserver.current;
if (!wrapper.current) {
return;
}
observer.observe(wrapper.current);
return () => {
observer.disconnect();
};
}, []);
return (
<div ref={wrapper} style={{ height }}>
{inView ? children : null}
</div>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment