Eric Jorgensen
Eric Jorgensen

Reputation: 2052

React: How to make collapsible elements that are fast?

I have an element at the top of my page that I want to be collapsible. The trouble is that if there are enough elements below it on the page (about 2000 or more), the act of collapsing/expanding causes the mouse to freeze for a few seconds. How can I add a collapsible element like this and still have a responsive UI?

My methods for collapsing that I have tried are rendering the collapsed element as "null" and rendering with height = 0. Both are slow.

The number of elements following the collapsible element in the example is not that big ~5000 - basically a table with a few hundred rows.

Code sandbox example here: https://codesandbox.io/s/2zi2s

Upvotes: 0

Views: 454

Answers (1)

rigojr
rigojr

Reputation: 361

I don't know if this can help. But on my work we implemented a component that can be collapsible with useLayoutEffect.

const InnerCardWrapper: React.FC<IInnerCardWrapper> = ({ isOpen, wrapperCssClasses = '', innerCssClasses = '', children }) => {
  const innerCardHeightMeasures = useRef(0);
  const [innerCardHeight, setInnerCardHeight] = useState(0);
  const elementId = uuid();

  useLayoutEffect(() => {
    const cardInnerContainer = document.getElementById(elementId);
    if (cardInnerContainer) {
      innerCardHeightMeasures.current = cardInnerContainer.clientHeight;
    }
    if (innerCardHeightMeasures.current > 0) {
      setInnerCardHeight(innerCardHeightMeasures.current);
    }
  }, [isOpen]);

  useEffect(() => {
    setInnerCardHeight(innerCardHeight === 0 ? innerCardHeightMeasures.current : 0);
  }, [isOpen]);

  return (
    <div
      style={{ height: innerCardHeight }}
      className={`overflow-hidden transition-all ${isOpen ? 'border-b border-gray-light mt-6' : ''} ${wrapperCssClasses}`}
    >
      <div id={elementId} className={`py-3 ${innerCssClasses}`}>
        {children}
      </div>
    </div>
  );
};

export default InnerCardWrapper;

We use TailwindCSS you can check the CSS equivalent here.

Hope this works, please let me know.

Upvotes: 1

Related Questions