useHeights.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
  2. import * as React from 'react';
  3. import { useEffect, useRef } from 'react';
  4. import CacheMap from "../utils/CacheMap";
  5. function parseNumber(value) {
  6. var num = parseFloat(value);
  7. return isNaN(num) ? 0 : num;
  8. }
  9. export default function useHeights(getKey, onItemAdd, onItemRemove) {
  10. var _React$useState = React.useState(0),
  11. _React$useState2 = _slicedToArray(_React$useState, 2),
  12. updatedMark = _React$useState2[0],
  13. setUpdatedMark = _React$useState2[1];
  14. var instanceRef = useRef(new Map());
  15. var heightsRef = useRef(new CacheMap());
  16. var promiseIdRef = useRef(0);
  17. function cancelRaf() {
  18. promiseIdRef.current += 1;
  19. }
  20. function collectHeight() {
  21. var sync = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  22. cancelRaf();
  23. var doCollect = function doCollect() {
  24. var changed = false;
  25. instanceRef.current.forEach(function (element, key) {
  26. if (element && element.offsetParent) {
  27. var offsetHeight = element.offsetHeight;
  28. var _getComputedStyle = getComputedStyle(element),
  29. marginTop = _getComputedStyle.marginTop,
  30. marginBottom = _getComputedStyle.marginBottom;
  31. var marginTopNum = parseNumber(marginTop);
  32. var marginBottomNum = parseNumber(marginBottom);
  33. var totalHeight = offsetHeight + marginTopNum + marginBottomNum;
  34. if (heightsRef.current.get(key) !== totalHeight) {
  35. heightsRef.current.set(key, totalHeight);
  36. changed = true;
  37. }
  38. }
  39. });
  40. // Always trigger update mark to tell parent that should re-calculate heights when resized
  41. if (changed) {
  42. setUpdatedMark(function (c) {
  43. return c + 1;
  44. });
  45. }
  46. };
  47. if (sync) {
  48. doCollect();
  49. } else {
  50. promiseIdRef.current += 1;
  51. var id = promiseIdRef.current;
  52. Promise.resolve().then(function () {
  53. if (id === promiseIdRef.current) {
  54. doCollect();
  55. }
  56. });
  57. }
  58. }
  59. function setInstanceRef(item, instance) {
  60. var key = getKey(item);
  61. var origin = instanceRef.current.get(key);
  62. if (instance) {
  63. instanceRef.current.set(key, instance);
  64. collectHeight();
  65. } else {
  66. instanceRef.current.delete(key);
  67. }
  68. // Instance changed
  69. if (!origin !== !instance) {
  70. if (instance) {
  71. onItemAdd === null || onItemAdd === void 0 || onItemAdd(item);
  72. } else {
  73. onItemRemove === null || onItemRemove === void 0 || onItemRemove(item);
  74. }
  75. }
  76. }
  77. useEffect(function () {
  78. return cancelRaf;
  79. }, []);
  80. return [setInstanceRef, collectHeight, heightsRef.current, updatedMark];
  81. }