useVirtualizedGrid.tsx 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import {
  2. DependencyList,
  3. RefObject,
  4. useCallback,
  5. useEffect,
  6. useMemo,
  7. useState,
  8. } from 'react';
  9. import {CellMeasurerCache, CellMeasurerCacheParams, MultiGrid} from 'react-virtualized';
  10. type Opts = {
  11. /**
  12. * Options for the CellMeasurerCache constructor
  13. */
  14. cellMeasurer: CellMeasurerCacheParams;
  15. /**
  16. * How many columns are being rendered
  17. * */
  18. columnCount: number;
  19. /**
  20. * List of other values that should trigger re-computing column sizes
  21. * */
  22. deps: DependencyList;
  23. /**
  24. * There must be one column with a dynamic width, so the table can fill all available width inside the container
  25. */
  26. dynamicColumnIndex: number;
  27. /**
  28. * The <MultiGrid> elem.
  29. */
  30. gridRef: RefObject<MultiGrid>;
  31. };
  32. function useVirtualizedGrid({
  33. cellMeasurer,
  34. columnCount,
  35. deps,
  36. dynamicColumnIndex,
  37. gridRef,
  38. }: Opts) {
  39. const cache = useMemo(() => new CellMeasurerCache(cellMeasurer), [cellMeasurer]);
  40. const [scrollBarWidth, setScrollBarWidth] = useState(0);
  41. const onWrapperResize = useCallback(() => {
  42. // TODO: debounce?
  43. gridRef.current?.recomputeGridSize({columnIndex: dynamicColumnIndex});
  44. }, [gridRef, dynamicColumnIndex]);
  45. // Recompute the width of the dynamic column when deps change (ie: a search/filter is applied)
  46. useEffect(onWrapperResize, [onWrapperResize, deps]);
  47. const onScrollbarPresenceChange = useCallback(({vertical, size}) => {
  48. setScrollBarWidth(vertical ? size : 0);
  49. }, []);
  50. const getColumnWidth = useCallback(
  51. (width: number) =>
  52. ({index}) => {
  53. if (index !== dynamicColumnIndex) {
  54. return cache.columnWidth({index});
  55. }
  56. const columns = Array.from(new Array(columnCount));
  57. const fullWidth = width - scrollBarWidth;
  58. // Take the full width available, and remove all the static/cached widths
  59. // so we know how much space is available for our dynamic column.
  60. const colWidth = columns.reduce(
  61. (remainingWidth, _, i) =>
  62. i === dynamicColumnIndex
  63. ? remainingWidth
  64. : remainingWidth - cache.columnWidth({index: i}),
  65. fullWidth
  66. );
  67. return Math.max(colWidth, 200);
  68. },
  69. [cache, columnCount, dynamicColumnIndex, scrollBarWidth]
  70. );
  71. return {
  72. cache,
  73. getColumnWidth,
  74. onScrollbarPresenceChange,
  75. onWrapperResize,
  76. };
  77. }
  78. export default useVirtualizedGrid;