virtual-scroller 1.12.2 → 1.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/CODE_OF_CONDUCT.md +78 -0
  3. package/README.md +1 -1
  4. package/bundle/index-bypass.html +2 -2
  5. package/bundle/index-grid.html +2 -2
  6. package/bundle/index-scrollableContainer.html +2 -2
  7. package/bundle/virtual-scroller-dom.js +1 -1
  8. package/bundle/virtual-scroller-dom.js.map +1 -1
  9. package/bundle/virtual-scroller-react.js +1 -1
  10. package/bundle/virtual-scroller-react.js.map +1 -1
  11. package/bundle/virtual-scroller.js +1 -1
  12. package/bundle/virtual-scroller.js.map +1 -1
  13. package/commonjs/Layout.js +10 -13
  14. package/commonjs/Layout.js.map +1 -1
  15. package/commonjs/Layout.test.js +20 -10
  16. package/commonjs/Layout.test.js.map +1 -1
  17. package/commonjs/Scroll.js +2 -1
  18. package/commonjs/Scroll.js.map +1 -1
  19. package/commonjs/{Resize.js → ScrollableContainerResizeHandler.js} +7 -7
  20. package/commonjs/ScrollableContainerResizeHandler.js.map +1 -0
  21. package/commonjs/VirtualScroller.constructor.js +5 -5
  22. package/commonjs/VirtualScroller.constructor.js.map +1 -1
  23. package/commonjs/VirtualScroller.items.js +1 -1
  24. package/commonjs/VirtualScroller.items.js.map +1 -1
  25. package/commonjs/VirtualScroller.js +67 -28
  26. package/commonjs/VirtualScroller.js.map +1 -1
  27. package/commonjs/VirtualScroller.layout.js +24 -22
  28. package/commonjs/VirtualScroller.layout.js.map +1 -1
  29. package/commonjs/{VirtualScroller.resize.js → VirtualScroller.onContainerResize.js} +2 -2
  30. package/commonjs/VirtualScroller.onContainerResize.js.map +1 -0
  31. package/commonjs/VirtualScroller.onRender.js +2 -2
  32. package/commonjs/VirtualScroller.onRender.js.map +1 -1
  33. package/commonjs/react/VirtualScroller.js +3 -0
  34. package/commonjs/react/VirtualScroller.js.map +1 -1
  35. package/commonjs/react/useEffectDontMountTwiceInStrictMode.js +83 -0
  36. package/commonjs/react/useEffectDontMountTwiceInStrictMode.js.map +1 -0
  37. package/commonjs/react/useInsertionEffectDontMountTwiceInStrictMode.js +20 -0
  38. package/commonjs/react/useInsertionEffectDontMountTwiceInStrictMode.js.map +1 -0
  39. package/commonjs/react/useLayoutEffectDontMountTwiceInStrictMode.js +20 -0
  40. package/commonjs/react/useLayoutEffectDontMountTwiceInStrictMode.js.map +1 -0
  41. package/commonjs/react/useState.js +13 -7
  42. package/commonjs/react/useState.js.map +1 -1
  43. package/commonjs/react/useStateNoStaleBug.js +59 -0
  44. package/commonjs/react/useStateNoStaleBug.js.map +1 -0
  45. package/modules/Layout.js +10 -13
  46. package/modules/Layout.js.map +1 -1
  47. package/modules/Layout.test.js +20 -10
  48. package/modules/Layout.test.js.map +1 -1
  49. package/modules/Scroll.js +2 -1
  50. package/modules/Scroll.js.map +1 -1
  51. package/modules/{Resize.js → ScrollableContainerResizeHandler.js} +7 -7
  52. package/modules/ScrollableContainerResizeHandler.js.map +1 -0
  53. package/modules/VirtualScroller.constructor.js +5 -5
  54. package/modules/VirtualScroller.constructor.js.map +1 -1
  55. package/modules/VirtualScroller.items.js +1 -1
  56. package/modules/VirtualScroller.items.js.map +1 -1
  57. package/modules/VirtualScroller.js +67 -28
  58. package/modules/VirtualScroller.js.map +1 -1
  59. package/modules/VirtualScroller.layout.js +24 -22
  60. package/modules/VirtualScroller.layout.js.map +1 -1
  61. package/modules/{VirtualScroller.resize.js → VirtualScroller.onContainerResize.js} +2 -2
  62. package/modules/VirtualScroller.onContainerResize.js.map +1 -0
  63. package/modules/VirtualScroller.onRender.js +2 -2
  64. package/modules/VirtualScroller.onRender.js.map +1 -1
  65. package/modules/react/VirtualScroller.js +3 -1
  66. package/modules/react/VirtualScroller.js.map +1 -1
  67. package/modules/react/useEffectDontMountTwiceInStrictMode.js +75 -0
  68. package/modules/react/useEffectDontMountTwiceInStrictMode.js.map +1 -0
  69. package/modules/react/useInsertionEffectDontMountTwiceInStrictMode.js +9 -0
  70. package/modules/react/useInsertionEffectDontMountTwiceInStrictMode.js.map +1 -0
  71. package/modules/react/useLayoutEffectDontMountTwiceInStrictMode.js +9 -0
  72. package/modules/react/useLayoutEffectDontMountTwiceInStrictMode.js.map +1 -0
  73. package/modules/react/useState.js +11 -8
  74. package/modules/react/useState.js.map +1 -1
  75. package/modules/react/useStateNoStaleBug.js +51 -0
  76. package/modules/react/useStateNoStaleBug.js.map +1 -0
  77. package/package.json +1 -1
  78. package/source/Layout.js +10 -13
  79. package/source/Layout.test.js +20 -10
  80. package/source/Scroll.js +1 -0
  81. package/source/{Resize.js → ScrollableContainerResizeHandler.js} +1 -1
  82. package/source/VirtualScroller.constructor.js +5 -5
  83. package/source/VirtualScroller.items.js +1 -1
  84. package/source/VirtualScroller.js +65 -25
  85. package/source/VirtualScroller.layout.js +22 -20
  86. package/source/{VirtualScroller.resize.js → VirtualScroller.onContainerResize.js} +1 -1
  87. package/source/VirtualScroller.onRender.js +2 -2
  88. package/source/react/VirtualScroller.js +3 -0
  89. package/source/react/useEffectDontMountTwiceInStrictMode.js +68 -0
  90. package/source/react/useInsertionEffectDontMountTwiceInStrictMode.js +10 -0
  91. package/source/react/useLayoutEffectDontMountTwiceInStrictMode.js +10 -0
  92. package/source/react/useState.js +8 -5
  93. package/source/react/useStateNoStaleBug.js +35 -0
  94. package/website/index-bypass.html +4 -14
  95. package/website/index-dom.html +1 -1
  96. package/website/index-grid.html +4 -4
  97. package/website/index-scrollableContainer.html +4 -4
  98. package/website/index-tbody-scrollableContainer.html +2 -0
  99. package/website/index-tbody.html +2 -0
  100. package/website/index.html +3 -3
  101. package/commonjs/Resize.js.map +0 -1
  102. package/commonjs/VirtualScroller.resize.js.map +0 -1
  103. package/modules/Resize.js.map +0 -1
  104. package/modules/VirtualScroller.resize.js.map +0 -1
@@ -0,0 +1,75 @@
1
+ import { useRef, useCallback } from 'react'; // A workaround for a React bug when `useInsertionEffect()` doesn't run twice on mount
2
+ // in "strict" mode unlike `useEffect()` and `useLayoutEffect()` do.
3
+ // https://github.com/facebook/react/issues/26320
4
+
5
+ export default function useEffectDontMountTwiceInStrictMode(useEffect, handler, dependencies) {
6
+ if (!Array.isArray(dependencies)) {
7
+ throw new Error('Dependencies argument must be an array');
8
+ }
9
+
10
+ var _useEffectStatus = useEffectStatus(),
11
+ onEffect = _useEffectStatus.onEffect;
12
+
13
+ var _usePrevousValue = usePrevousValue(dependencies),
14
+ onChange = _usePrevousValue.onChange;
15
+
16
+ useEffect(function () {
17
+ var _onEffect = onEffect(),
18
+ isInitialRun = _onEffect.isInitialRun;
19
+
20
+ var previousDependencies = onChange(dependencies);
21
+
22
+ if (isInitialRun || !isShallowEqualArrays(previousDependencies, dependencies)) {
23
+ var cleanUpFunction = handler();
24
+
25
+ if (typeof cleanUpFunction === 'function') {
26
+ throw new Error('An effect can\'t return a clean-up function when used with `useEffectDontMountTwiceInStrictMode()` because the clean-up function won\'t behave correctly in that case');
27
+ }
28
+ }
29
+ }, dependencies);
30
+ }
31
+
32
+ function useEffectStatus() {
33
+ var hasMounted = useRef(false);
34
+ var onEffect = useCallback(function () {
35
+ var wasAlreadyMounted = hasMounted.current;
36
+ hasMounted.current = true;
37
+ return {
38
+ isInitialRun: !wasAlreadyMounted
39
+ };
40
+ }, []);
41
+ return {
42
+ onEffect: onEffect
43
+ };
44
+ }
45
+
46
+ function usePrevousValue(value) {
47
+ var prevValue = useRef(value);
48
+ var onChange = useCallback(function (value) {
49
+ var previousValue = prevValue.current;
50
+ prevValue.current = value;
51
+ return previousValue;
52
+ }, []);
53
+ return {
54
+ onChange: onChange
55
+ };
56
+ }
57
+
58
+ function isShallowEqualArrays(a, b) {
59
+ if (a.length !== b.length) {
60
+ return false;
61
+ }
62
+
63
+ var i = 0;
64
+
65
+ while (i < a.length) {
66
+ if (a[i] !== b[i]) {
67
+ return false;
68
+ }
69
+
70
+ i++;
71
+ }
72
+
73
+ return true;
74
+ }
75
+ //# sourceMappingURL=useEffectDontMountTwiceInStrictMode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEffectDontMountTwiceInStrictMode.js","names":["useRef","useCallback","useEffectDontMountTwiceInStrictMode","useEffect","handler","dependencies","Array","isArray","Error","useEffectStatus","onEffect","usePrevousValue","onChange","isInitialRun","previousDependencies","isShallowEqualArrays","cleanUpFunction","hasMounted","wasAlreadyMounted","current","value","prevValue","previousValue","a","b","length","i"],"sources":["../../source/react/useEffectDontMountTwiceInStrictMode.js"],"sourcesContent":["import { useRef, useCallback } from 'react'\r\n\r\n// A workaround for a React bug when `useInsertionEffect()` doesn't run twice on mount\r\n// in \"strict\" mode unlike `useEffect()` and `useLayoutEffect()` do.\r\n// https://github.com/facebook/react/issues/26320\r\nexport default function useEffectDontMountTwiceInStrictMode(useEffect, handler, dependencies) {\r\n if (!Array.isArray(dependencies)) {\r\n throw new Error('Dependencies argument must be an array')\r\n }\r\n\r\n const { onEffect } = useEffectStatus()\r\n const { onChange } = usePrevousValue(dependencies)\r\n\r\n useEffect(() => {\r\n const { isInitialRun } = onEffect()\r\n const previousDependencies = onChange(dependencies)\r\n if (isInitialRun || !isShallowEqualArrays(previousDependencies, dependencies)) {\r\n const cleanUpFunction = handler()\r\n if (typeof cleanUpFunction === 'function') {\r\n throw new Error('An effect can\\'t return a clean-up function when used with `useEffectDontMountTwiceInStrictMode()` because the clean-up function won\\'t behave correctly in that case')\r\n }\r\n }\r\n }, dependencies)\r\n}\r\n\r\nfunction useEffectStatus() {\r\n const hasMounted = useRef(false)\r\n\r\n const onEffect = useCallback(() => {\r\n const wasAlreadyMounted = hasMounted.current\r\n hasMounted.current = true\r\n return {\r\n isInitialRun: !wasAlreadyMounted\r\n }\r\n }, [])\r\n\r\n return {\r\n onEffect\r\n }\r\n}\r\n\r\nfunction usePrevousValue(value) {\r\n const prevValue = useRef(value)\r\n\r\n const onChange = useCallback((value) => {\r\n const previousValue = prevValue.current\r\n prevValue.current = value\r\n return previousValue\r\n }, [])\r\n\r\n return {\r\n onChange\r\n }\r\n}\r\n\r\nfunction isShallowEqualArrays(a, b) {\r\n if (a.length !== b.length) {\r\n return false\r\n }\r\n let i = 0\r\n while (i < a.length) {\r\n if (a[i] !== b[i]) {\r\n return false\r\n }\r\n i++\r\n }\r\n return true\r\n}"],"mappings":"AAAA,SAASA,MAAT,EAAiBC,WAAjB,QAAoC,OAApC,C,CAEA;AACA;AACA;;AACA,eAAe,SAASC,mCAAT,CAA6CC,SAA7C,EAAwDC,OAAxD,EAAiEC,YAAjE,EAA+E;EAC5F,IAAI,CAACC,KAAK,CAACC,OAAN,CAAcF,YAAd,CAAL,EAAkC;IAChC,MAAM,IAAIG,KAAJ,CAAU,wCAAV,CAAN;EACD;;EAED,uBAAqBC,eAAe,EAApC;EAAA,IAAQC,QAAR,oBAAQA,QAAR;;EACA,uBAAqBC,eAAe,CAACN,YAAD,CAApC;EAAA,IAAQO,QAAR,oBAAQA,QAAR;;EAEAT,SAAS,CAAC,YAAM;IACd,gBAAyBO,QAAQ,EAAjC;IAAA,IAAQG,YAAR,aAAQA,YAAR;;IACA,IAAMC,oBAAoB,GAAGF,QAAQ,CAACP,YAAD,CAArC;;IACA,IAAIQ,YAAY,IAAI,CAACE,oBAAoB,CAACD,oBAAD,EAAuBT,YAAvB,CAAzC,EAA+E;MAC7E,IAAMW,eAAe,GAAGZ,OAAO,EAA/B;;MACA,IAAI,OAAOY,eAAP,KAA2B,UAA/B,EAA2C;QACzC,MAAM,IAAIR,KAAJ,CAAU,uKAAV,CAAN;MACD;IACF;EACF,CATQ,EASNH,YATM,CAAT;AAUD;;AAED,SAASI,eAAT,GAA2B;EACzB,IAAMQ,UAAU,GAAGjB,MAAM,CAAC,KAAD,CAAzB;EAEA,IAAMU,QAAQ,GAAGT,WAAW,CAAC,YAAM;IACjC,IAAMiB,iBAAiB,GAAGD,UAAU,CAACE,OAArC;IACAF,UAAU,CAACE,OAAX,GAAqB,IAArB;IACA,OAAO;MACLN,YAAY,EAAE,CAACK;IADV,CAAP;EAGD,CAN2B,EAMzB,EANyB,CAA5B;EAQA,OAAO;IACLR,QAAQ,EAARA;EADK,CAAP;AAGD;;AAED,SAASC,eAAT,CAAyBS,KAAzB,EAAgC;EAC9B,IAAMC,SAAS,GAAGrB,MAAM,CAACoB,KAAD,CAAxB;EAEA,IAAMR,QAAQ,GAAGX,WAAW,CAAC,UAACmB,KAAD,EAAW;IACtC,IAAME,aAAa,GAAGD,SAAS,CAACF,OAAhC;IACAE,SAAS,CAACF,OAAV,GAAoBC,KAApB;IACA,OAAOE,aAAP;EACD,CAJ2B,EAIzB,EAJyB,CAA5B;EAMA,OAAO;IACLV,QAAQ,EAARA;EADK,CAAP;AAGD;;AAED,SAASG,oBAAT,CAA8BQ,CAA9B,EAAiCC,CAAjC,EAAoC;EAClC,IAAID,CAAC,CAACE,MAAF,KAAaD,CAAC,CAACC,MAAnB,EAA2B;IACzB,OAAO,KAAP;EACD;;EACD,IAAIC,CAAC,GAAG,CAAR;;EACA,OAAOA,CAAC,GAAGH,CAAC,CAACE,MAAb,EAAqB;IACnB,IAAIF,CAAC,CAACG,CAAD,CAAD,KAASF,CAAC,CAACE,CAAD,CAAd,EAAmB;MACjB,OAAO,KAAP;IACD;;IACDA,CAAC;EACF;;EACD,OAAO,IAAP;AACD"}
@@ -0,0 +1,9 @@
1
+ import { useInsertionEffect } from 'react';
2
+ import useEffectDontMountTwiceInStrictMode from './useEffectDontMountTwiceInStrictMode.js'; // A workaround for a React bug when `useInsertionEffect()` doesn't run twice on mount
3
+ // in "strict" mode unlike `useEffect()` and `useLayoutEffect()` do.
4
+ // https://github.com/facebook/react/issues/26320
5
+
6
+ export default function useInsertionEffectDontMountTwiceInStrictMode(handler, dependencies) {
7
+ return useEffectDontMountTwiceInStrictMode(useInsertionEffect, handler, dependencies);
8
+ }
9
+ //# sourceMappingURL=useInsertionEffectDontMountTwiceInStrictMode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInsertionEffectDontMountTwiceInStrictMode.js","names":["useInsertionEffect","useEffectDontMountTwiceInStrictMode","useInsertionEffectDontMountTwiceInStrictMode","handler","dependencies"],"sources":["../../source/react/useInsertionEffectDontMountTwiceInStrictMode.js"],"sourcesContent":["import { useInsertionEffect } from 'react'\r\n\r\nimport useEffectDontMountTwiceInStrictMode from './useEffectDontMountTwiceInStrictMode.js'\r\n\r\n// A workaround for a React bug when `useInsertionEffect()` doesn't run twice on mount\r\n// in \"strict\" mode unlike `useEffect()` and `useLayoutEffect()` do.\r\n// https://github.com/facebook/react/issues/26320\r\nexport default function useInsertionEffectDontMountTwiceInStrictMode(handler, dependencies) {\r\n return useEffectDontMountTwiceInStrictMode(useInsertionEffect, handler, dependencies)\r\n}"],"mappings":"AAAA,SAASA,kBAAT,QAAmC,OAAnC;AAEA,OAAOC,mCAAP,MAAgD,0CAAhD,C,CAEA;AACA;AACA;;AACA,eAAe,SAASC,4CAAT,CAAsDC,OAAtD,EAA+DC,YAA/D,EAA6E;EAC1F,OAAOH,mCAAmC,CAACD,kBAAD,EAAqBG,OAArB,EAA8BC,YAA9B,CAA1C;AACD"}
@@ -0,0 +1,9 @@
1
+ import { useLayoutEffect } from 'react';
2
+ import useEffectDontMountTwiceInStrictMode from './useEffectDontMountTwiceInStrictMode.js'; // A workaround for a React bug when `useInsertionEffect()` doesn't run twice on mount
3
+ // in "strict" mode unlike `useEffect()` and `useLayoutEffect()` do.
4
+ // https://github.com/facebook/react/issues/26320
5
+
6
+ export default function useLayoutEffectDontMountTwiceInStrictMode(handler, dependencies) {
7
+ return useEffectDontMountTwiceInStrictMode(useLayoutEffect, handler, dependencies);
8
+ }
9
+ //# sourceMappingURL=useLayoutEffectDontMountTwiceInStrictMode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLayoutEffectDontMountTwiceInStrictMode.js","names":["useLayoutEffect","useEffectDontMountTwiceInStrictMode","useLayoutEffectDontMountTwiceInStrictMode","handler","dependencies"],"sources":["../../source/react/useLayoutEffectDontMountTwiceInStrictMode.js"],"sourcesContent":["import { useLayoutEffect } from 'react'\r\n\r\nimport useEffectDontMountTwiceInStrictMode from './useEffectDontMountTwiceInStrictMode.js'\r\n\r\n// A workaround for a React bug when `useInsertionEffect()` doesn't run twice on mount\r\n// in \"strict\" mode unlike `useEffect()` and `useLayoutEffect()` do.\r\n// https://github.com/facebook/react/issues/26320\r\nexport default function useLayoutEffectDontMountTwiceInStrictMode(handler, dependencies) {\r\n return useEffectDontMountTwiceInStrictMode(useLayoutEffect, handler, dependencies)\r\n}"],"mappings":"AAAA,SAASA,eAAT,QAAgC,OAAhC;AAEA,OAAOC,mCAAP,MAAgD,0CAAhD,C,CAEA;AACA;AACA;;AACA,eAAe,SAASC,yCAAT,CAAmDC,OAAnD,EAA4DC,YAA5D,EAA0E;EACvF,OAAOH,mCAAmC,CAACD,eAAD,EAAkBG,OAAlB,EAA2BC,YAA3B,CAA1C;AACD"}
@@ -12,7 +12,10 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
12
12
 
13
13
  import log, { isDebug } from '../utility/debug.js';
14
14
  import getStateSnapshot from '../utility/getStateSnapshot.js';
15
- import { useState, useRef, useCallback, useLayoutEffect, useInsertionEffect } from 'react'; // Creates state management functions.
15
+ import { useRef, useCallback } from 'react';
16
+ import useStateNoStaleBug from './useStateNoStaleBug.js';
17
+ import useInsertionEffectDontMountTwiceInStrictMode from './useInsertionEffectDontMountTwiceInStrictMode.js';
18
+ import useLayoutEffectDontMountTwiceInStrictMode from './useLayoutEffectDontMountTwiceInStrictMode.js'; // Creates state management functions.
16
19
 
17
20
  export default function _useState(_ref) {
18
21
  var initialState = _ref.initialState,
@@ -24,10 +27,10 @@ export default function _useState(_ref) {
24
27
  // `VirtualScroller` state gets updated from this variable.
25
28
  // The reason for that is that `VirtualScroller` state must always
26
29
  // correspond exactly to what's currently rendered on the screen.
27
- var _useState2 = useState(initialState),
28
- _useState3 = _slicedToArray(_useState2, 2),
29
- _newState = _useState3[0],
30
- _setNewState = _useState3[1]; // This `state` reference is what `VirtualScroller` uses internally.
30
+ var _useStateNoStaleBug = useStateNoStaleBug(initialState),
31
+ _useStateNoStaleBug2 = _slicedToArray(_useStateNoStaleBug, 2),
32
+ _newState = _useStateNoStaleBug2[0],
33
+ _setNewState = _useStateNoStaleBug2[1]; // This `state` reference is what `VirtualScroller` uses internally.
31
34
  // It's the "source of truth" on the actual `VirtualScroller` state.
32
35
 
33
36
 
@@ -145,7 +148,7 @@ export default function _useState(_ref) {
145
148
  // it could be replaced with using `ref`s on `ItemComponent`s to measure the DOM element heights.
146
149
  //
147
150
 
148
- useInsertionEffect(function () {
151
+ useInsertionEffectDontMountTwiceInStrictMode(function () {
149
152
  // Update the actual `VirtualScroller` state right before the DOM changes
150
153
  // are going to be applied for the requested state update.
151
154
  //
@@ -168,13 +171,13 @@ export default function _useState(_ref) {
168
171
  // This hook doesn't do anything at the initial render.
169
172
  //
170
173
  if (isDebug()) {
171
- log('React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~');
174
+ log('React: ~ The requested state is about to be applied in DOM. Setting it as the `VirtualScroller` state. ~');
172
175
  log(getStateSnapshot(_newState));
173
176
  }
174
177
 
175
178
  setState(_newState);
176
179
  }, [_newState]);
177
- useLayoutEffect(function () {
180
+ useLayoutEffectDontMountTwiceInStrictMode(function () {
178
181
  // Call `onRender()` right after a requested state update has been applied,
179
182
  // and also right after the initial render.
180
183
  onRender();
@@ -1 +1 @@
1
- {"version":3,"file":"useState.js","names":["log","isDebug","getStateSnapshot","useState","useRef","useCallback","useLayoutEffect","useInsertionEffect","_useState","initialState","onRender","itemsProperty","_newState","_setNewState","state","getState","current","setState","newState","stateToRender"],"sources":["../../source/react/useState.js"],"sourcesContent":["import log, { isDebug } from '../utility/debug.js'\r\nimport getStateSnapshot from '../utility/getStateSnapshot.js'\r\n\r\nimport { useState, useRef, useCallback, useLayoutEffect, useInsertionEffect } from 'react'\r\n\r\n// Creates state management functions.\r\nexport default function _useState({\r\n\tinitialState,\r\n\tonRender,\r\n\titemsProperty\r\n}) {\r\n\t// This is a state variable that is used to re-render the component.\r\n\t// Right after the component has finished re-rendering,\r\n\t// `VirtualScroller` state gets updated from this variable.\r\n\t// The reason for that is that `VirtualScroller` state must always\r\n\t// correspond exactly to what's currently rendered on the screen.\r\n\tconst [_newState, _setNewState] = useState(initialState)\r\n\r\n\t// This `state` reference is what `VirtualScroller` uses internally.\r\n\t// It's the \"source of truth\" on the actual `VirtualScroller` state.\r\n\tconst state = useRef(initialState)\r\n\r\n\tconst getState = useCallback(() => {\r\n\t\treturn state.current\r\n\t}, [])\r\n\r\n\tconst setState = useCallback((newState) => {\r\n\t\tstate.current = newState\r\n\t}, [])\r\n\r\n\t// Updating of the actual `VirtualScroller` state is done in a\r\n\t// `useInsertionEffect()` rather than in a `useLayoutEffect()`.\r\n\t//\r\n\t// The reason is that using `useLayoutEffect()` would result in\r\n\t// \"breaking\" the `<VirtualScroller/>` when an `itemComponent`\r\n\t// called `onHeightDidChange()` from its own `useLayoutEffect()`.\r\n\t// In those cases, the `itemCompoent`'s effect would run before\r\n\t// the `<VirtualScroller/>`'s effect, resulting in\r\n\t// `VirtualScroller.onItemHeightDidChange(i)` being run at a moment in time\r\n\t// when the DOM has already been updated for the next `VirtualScroller` state\r\n\t// but the actual `VirtualScroller` state is still a previous (\"stale\") one\r\n\t// containing \"stale\" first/last shown item indexes, which would result in an\r\n\t// \"index out of bounds\" error when `onItemHeightDidChange(i)` tries to access\r\n\t// and measure the DOM element from item index `i` which doesn't already/yet exist.\r\n\t//\r\n\t// An example of such situation could be seen from a `VirtualScroller` debug log\r\n\t// which was captured for a case when using `useLayoutEffect()` to update the\r\n\t// \"actual\" `VirtualScroller` state after the corresponding DOM changes have been applied:\r\n\r\n\t// The user has scrolled far enough: perform a re-layout\r\n\t// ~ Update Layout (on scroll) ~\r\n\t//\r\n\t// Item index 2 height is required for calculations but hasn't been measured yet. Mark the item as \"shown\", rerender the list, measure the item's height and redo the layout.\r\n\t//\r\n\t// ~ Calculated Layout ~\r\n\t// Columns count 1\r\n\t// First shown item index 2\r\n\t// Last shown item index 5\r\n\t// …\r\n\t// Item heights (231) [1056.578125, 783.125, empty × 229]\r\n\t// Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]\r\n\t//\r\n\t// ~ Set state ~\r\n\t// {firstShownItemIndex: 2, lastShownItemIndex: 5, …}\r\n\t//\r\n\t// ~ Rendered ~\r\n\t// State {firstShownItemIndex: 2, lastShownItemIndex: 5, …}\r\n\t//\r\n\t// ~ Measure item heights ~\r\n\t// Item index 2 height 719.8828125\r\n\t// Item index 3 height 961.640625\r\n\t// Item index 4 height 677.6640625\r\n\t// Item index 5 height 1510.1953125\r\n\t//\r\n\t// ~ Update Layout (on non-measured item heights have been measured) ~\r\n\t//\r\n\t// ~ Calculated Layout ~\r\n\t// Columns count 1\r\n\t// First shown item index 4\r\n\t// Last shown item index 5\r\n\t// …\r\n\t// Item heights (231) [1056.578125, 783.125, 719.8828125, 961.640625, 677.6640625, 1510.1953125, empty × 225]\r\n\t// Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]\r\n\t//\r\n\t// ~ Set state ~\r\n\t// {firstShownItemIndex: 4, lastShownItemIndex: 5, beforeItemsHeight: 3521.2265625, afterItemsHeight: 214090.72265624942}\r\n\t//\r\n\t// ~ On Item Height Did Change was called ~\r\n\t// Item index 5\r\n\t// ~ Re-measure item height ~\r\n\t// ERROR \"onItemHeightDidChange()\" has been called for item index 5 but the item is not currently rendered and can't be measured. The exact error was: Element with index 3 was not found in the list of Rendered Item Elements in the Items Container of Virtual Scroller. There're only 2 Elements there.\r\n\t//\r\n\t// React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~\r\n\t// {firstShownItemIndex: 4, lastShownItemIndex: 5, …}\r\n\t//\r\n\t// ~ Rendered ~\r\n\r\n\t// \"~ Rendered ~\" is what gets output when `onRender()` function gets called.\r\n\t// It means that `useLayoutEffect()` was triggered after `onItemHeightDidChange(i)`\r\n\t// was called and after the \"ERROR\" happened.\r\n\t//\r\n\t// The \"ERROR\" happened because new item indexes 4…5 were actually rendered instead of\r\n\t// item indexes 2…5 by the time the application called `onItemHeightDidChange(i)` function\r\n\t// inside `itemComponent`'s `useLayoutEffect()`.\r\n\t// Item indexes 4…5 is what was requested in a `setState()` call, which called `_setNewState()`.\r\n\t// This means that `_newState` changes have been applied to the DOM\r\n\t// but `useLayoutEffect()` wasn't triggered immediately after that.\r\n\t// Instead, it was triggered a right after the `itemComponent`'s `useLayoutEffect()`\r\n\t// because child effects run before parent effects.\r\n\t// So, the `itemComponent`'s `onHeightDidChange()` function call caught the\r\n\t// `VirtualScroller` in an inconsistent state.\r\n\t//\r\n\t// To fix that, `useLayoutEffect()` gets replaced with `useInsertionEffect()`:\r\n\t// https://blog.saeloun.com/2022/06/02/react-18-useinsertioneffect\r\n\t// https://beta.reactjs.org/reference/react/useInsertionEffect\r\n\t//\r\n\t// After replacing `useLayoutEffect()` with `useInsertionEffect()`,\r\n\t// the log shows that there's no more error:\r\n\t//\r\n\t// ~ Set state ~\r\n\t// {firstShownItemIndex: 0, lastShownItemIndex: 2, …}\r\n\t//\r\n\t// React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~\r\n\t// {firstShownItemIndex: 0, lastShownItemIndex: 2, …}\r\n\t//\r\n\t// ~ On Item Height Did Change was called ~\r\n\t// Item index 0\r\n\t// ~ Re-measure item height ~\r\n\t// Previous height 917\r\n\t// New height 1064.453125\r\n\t// ~ Item height has changed ~\r\n\t//\r\n\t// An alternative solution would be demanding the `itemComponent` to\r\n\t// accept a `ref` and then measuring the corresponding DOM element height\r\n\t// directly using the `ref`-ed DOM element rather than searching for that\r\n\t// DOM element in the `ItemsContainer`.\r\n\t// So if `useInsertionEffect()` gets removed from React in some hypothetical future,\r\n\t// it could be replaced with using `ref`s on `ItemComponent`s to measure the DOM element heights.\r\n\t//\r\n\tuseInsertionEffect(() => {\r\n\t\t// Update the actual `VirtualScroller` state right before the DOM changes\r\n\t\t// are going to be applied for the requested state update.\r\n\t\t//\r\n\t\t// This hook will run right before `useLayoutEffect()`.\r\n\t\t//\r\n\t\t// It doesn't make any difference which one of the two hooks to use to update\r\n\t\t// the actual `VirtualScroller` state in this scenario because the two hooks\r\n\t\t// run synchronously one right after another (insertion effect → DOM update → layout effect)\r\n\t\t// without any free space for any `VirtualScroller` code (like the scroll event handler)\r\n\t\t// to squeeze in and run in-between them, so the `VirtualScroller`'s `state`\r\n\t\t// is always gonna stay consistent with what's currently rendered on screen\r\n\t\t// from the `VirtualScroler`'s point of view, and the short transition period\r\n\t\t// it simply doesn't see because it doesn't \"wake up\" during that period.\r\n\t\t//\r\n\t\t// Updating the actual `VirtualScroller` state right before `useLayoutEffect()`\r\n\t\t// fixes the bug when an `itemComponent` calls `onHeightDidChange()` in its own\r\n\t\t// `useLayoutEffect()` which would run before this `useLayoutEffect()`\r\n\t\t// because children's effects run before parent's.\r\n\t\t//\r\n\t\t// This hook doesn't do anything at the initial render.\r\n\t\t//\r\n\t\tif (isDebug()) {\r\n\t\t\tlog('React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~')\r\n\t\t\tlog(getStateSnapshot(_newState))\r\n\t\t}\r\n\t\tsetState(_newState)\r\n\t}, [_newState])\r\n\r\n\tuseLayoutEffect(() => {\r\n\t\t// Call `onRender()` right after a requested state update has been applied,\r\n\t\t// and also right after the initial render.\r\n\t\tonRender()\r\n\t}, [_newState])\r\n\r\n\treturn {\r\n\t\t// This is the state the component should render.\r\n\t\tstateToRender: _newState,\r\n\r\n\t\t// Returns the current state of the `VirtualScroller`.\r\n\t\t// This function is used in the `VirtualScroller` itself\r\n\t\t// because the `state` is managed outside of it.\r\n\t\tgetState,\r\n\r\n\t\t// Requests a state update.\r\n\t\tsetState: _setNewState\r\n\t}\r\n}"],"mappings":";;;;;;;;;;;;AAAA,OAAOA,GAAP,IAAcC,OAAd,QAA6B,qBAA7B;AACA,OAAOC,gBAAP,MAA6B,gCAA7B;AAEA,SAASC,QAAT,EAAmBC,MAAnB,EAA2BC,WAA3B,EAAwCC,eAAxC,EAAyDC,kBAAzD,QAAmF,OAAnF,C,CAEA;;AACA,eAAe,SAASC,SAAT,OAIZ;EAAA,IAHFC,YAGE,QAHFA,YAGE;EAAA,IAFFC,QAEE,QAFFA,QAEE;EAAA,IADFC,aACE,QADFA,aACE;;EACF;EACA;EACA;EACA;EACA;EACA,iBAAkCR,QAAQ,CAACM,YAAD,CAA1C;EAAA;EAAA,IAAOG,SAAP;EAAA,IAAkBC,YAAlB,iBANE,CAQF;EACA;;;EACA,IAAMC,KAAK,GAAGV,MAAM,CAACK,YAAD,CAApB;EAEA,IAAMM,QAAQ,GAAGV,WAAW,CAAC,YAAM;IAClC,OAAOS,KAAK,CAACE,OAAb;EACA,CAF2B,EAEzB,EAFyB,CAA5B;EAIA,IAAMC,QAAQ,GAAGZ,WAAW,CAAC,UAACa,QAAD,EAAc;IAC1CJ,KAAK,CAACE,OAAN,GAAgBE,QAAhB;EACA,CAF2B,EAEzB,EAFyB,CAA5B,CAhBE,CAoBF;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EACAX,kBAAkB,CAAC,YAAM;IACxB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,IAAIN,OAAO,EAAX,EAAe;MACdD,GAAG,CAAC,sGAAD,CAAH;MACAA,GAAG,CAACE,gBAAgB,CAACU,SAAD,CAAjB,CAAH;IACA;;IACDK,QAAQ,CAACL,SAAD,CAAR;EACA,CA3BiB,EA2Bf,CAACA,SAAD,CA3Be,CAAlB;EA6BAN,eAAe,CAAC,YAAM;IACrB;IACA;IACAI,QAAQ;EACR,CAJc,EAIZ,CAACE,SAAD,CAJY,CAAf;EAMA,OAAO;IACN;IACAO,aAAa,EAAEP,SAFT;IAIN;IACA;IACA;IACAG,QAAQ,EAARA,QAPM;IASN;IACAE,QAAQ,EAAEJ;EAVJ,CAAP;AAYA"}
1
+ {"version":3,"file":"useState.js","names":["log","isDebug","getStateSnapshot","useRef","useCallback","useStateNoStaleBug","useInsertionEffectDontMountTwiceInStrictMode","useLayoutEffectDontMountTwiceInStrictMode","_useState","initialState","onRender","itemsProperty","_newState","_setNewState","state","getState","current","setState","newState","stateToRender"],"sources":["../../source/react/useState.js"],"sourcesContent":["import log, { isDebug } from '../utility/debug.js'\r\nimport getStateSnapshot from '../utility/getStateSnapshot.js'\r\n\r\nimport { useRef, useCallback } from 'react'\r\nimport useStateNoStaleBug from './useStateNoStaleBug.js'\r\nimport useInsertionEffectDontMountTwiceInStrictMode from './useInsertionEffectDontMountTwiceInStrictMode.js'\r\nimport useLayoutEffectDontMountTwiceInStrictMode from './useLayoutEffectDontMountTwiceInStrictMode.js'\r\n\r\n// Creates state management functions.\r\nexport default function _useState({\r\n\tinitialState,\r\n\tonRender,\r\n\titemsProperty\r\n}) {\r\n\t// This is a state variable that is used to re-render the component.\r\n\t// Right after the component has finished re-rendering,\r\n\t// `VirtualScroller` state gets updated from this variable.\r\n\t// The reason for that is that `VirtualScroller` state must always\r\n\t// correspond exactly to what's currently rendered on the screen.\r\n\tconst [_newState, _setNewState] = useStateNoStaleBug(initialState)\r\n\r\n\t// This `state` reference is what `VirtualScroller` uses internally.\r\n\t// It's the \"source of truth\" on the actual `VirtualScroller` state.\r\n\tconst state = useRef(initialState)\r\n\r\n\tconst getState = useCallback(() => {\r\n\t\treturn state.current\r\n\t}, [])\r\n\r\n\tconst setState = useCallback((newState) => {\r\n\t\tstate.current = newState\r\n\t}, [])\r\n\r\n\t// Updating of the actual `VirtualScroller` state is done in a\r\n\t// `useInsertionEffect()` rather than in a `useLayoutEffect()`.\r\n\t//\r\n\t// The reason is that using `useLayoutEffect()` would result in\r\n\t// \"breaking\" the `<VirtualScroller/>` when an `itemComponent`\r\n\t// called `onHeightDidChange()` from its own `useLayoutEffect()`.\r\n\t// In those cases, the `itemCompoent`'s effect would run before\r\n\t// the `<VirtualScroller/>`'s effect, resulting in\r\n\t// `VirtualScroller.onItemHeightDidChange(i)` being run at a moment in time\r\n\t// when the DOM has already been updated for the next `VirtualScroller` state\r\n\t// but the actual `VirtualScroller` state is still a previous (\"stale\") one\r\n\t// containing \"stale\" first/last shown item indexes, which would result in an\r\n\t// \"index out of bounds\" error when `onItemHeightDidChange(i)` tries to access\r\n\t// and measure the DOM element from item index `i` which doesn't already/yet exist.\r\n\t//\r\n\t// An example of such situation could be seen from a `VirtualScroller` debug log\r\n\t// which was captured for a case when using `useLayoutEffect()` to update the\r\n\t// \"actual\" `VirtualScroller` state after the corresponding DOM changes have been applied:\r\n\r\n\t// The user has scrolled far enough: perform a re-layout\r\n\t// ~ Update Layout (on scroll) ~\r\n\t//\r\n\t// Item index 2 height is required for calculations but hasn't been measured yet. Mark the item as \"shown\", rerender the list, measure the item's height and redo the layout.\r\n\t//\r\n\t// ~ Calculated Layout ~\r\n\t// Columns count 1\r\n\t// First shown item index 2\r\n\t// Last shown item index 5\r\n\t// …\r\n\t// Item heights (231) [1056.578125, 783.125, empty × 229]\r\n\t// Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]\r\n\t//\r\n\t// ~ Set state ~\r\n\t// {firstShownItemIndex: 2, lastShownItemIndex: 5, …}\r\n\t//\r\n\t// ~ Rendered ~\r\n\t// State {firstShownItemIndex: 2, lastShownItemIndex: 5, …}\r\n\t//\r\n\t// ~ Measure item heights ~\r\n\t// Item index 2 height 719.8828125\r\n\t// Item index 3 height 961.640625\r\n\t// Item index 4 height 677.6640625\r\n\t// Item index 5 height 1510.1953125\r\n\t//\r\n\t// ~ Update Layout (on non-measured item heights have been measured) ~\r\n\t//\r\n\t// ~ Calculated Layout ~\r\n\t// Columns count 1\r\n\t// First shown item index 4\r\n\t// Last shown item index 5\r\n\t// …\r\n\t// Item heights (231) [1056.578125, 783.125, 719.8828125, 961.640625, 677.6640625, 1510.1953125, empty × 225]\r\n\t// Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]\r\n\t//\r\n\t// ~ Set state ~\r\n\t// {firstShownItemIndex: 4, lastShownItemIndex: 5, beforeItemsHeight: 3521.2265625, afterItemsHeight: 214090.72265624942}\r\n\t//\r\n\t// ~ On Item Height Did Change was called ~\r\n\t// Item index 5\r\n\t// ~ Re-measure item height ~\r\n\t// ERROR \"onItemHeightDidChange()\" has been called for item index 5 but the item is not currently rendered and can't be measured. The exact error was: Element with index 3 was not found in the list of Rendered Item Elements in the Items Container of Virtual Scroller. There're only 2 Elements there.\r\n\t//\r\n\t// React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~\r\n\t// {firstShownItemIndex: 4, lastShownItemIndex: 5, …}\r\n\t//\r\n\t// ~ Rendered ~\r\n\r\n\t// \"~ Rendered ~\" is what gets output when `onRender()` function gets called.\r\n\t// It means that `useLayoutEffect()` was triggered after `onItemHeightDidChange(i)`\r\n\t// was called and after the \"ERROR\" happened.\r\n\t//\r\n\t// The \"ERROR\" happened because new item indexes 4…5 were actually rendered instead of\r\n\t// item indexes 2…5 by the time the application called `onItemHeightDidChange(i)` function\r\n\t// inside `itemComponent`'s `useLayoutEffect()`.\r\n\t// Item indexes 4…5 is what was requested in a `setState()` call, which called `_setNewState()`.\r\n\t// This means that `_newState` changes have been applied to the DOM\r\n\t// but `useLayoutEffect()` wasn't triggered immediately after that.\r\n\t// Instead, it was triggered a right after the `itemComponent`'s `useLayoutEffect()`\r\n\t// because child effects run before parent effects.\r\n\t// So, the `itemComponent`'s `onHeightDidChange()` function call caught the\r\n\t// `VirtualScroller` in an inconsistent state.\r\n\t//\r\n\t// To fix that, `useLayoutEffect()` gets replaced with `useInsertionEffect()`:\r\n\t// https://blog.saeloun.com/2022/06/02/react-18-useinsertioneffect\r\n\t// https://beta.reactjs.org/reference/react/useInsertionEffect\r\n\t//\r\n\t// After replacing `useLayoutEffect()` with `useInsertionEffect()`,\r\n\t// the log shows that there's no more error:\r\n\t//\r\n\t// ~ Set state ~\r\n\t// {firstShownItemIndex: 0, lastShownItemIndex: 2, …}\r\n\t//\r\n\t// React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~\r\n\t// {firstShownItemIndex: 0, lastShownItemIndex: 2, …}\r\n\t//\r\n\t// ~ On Item Height Did Change was called ~\r\n\t// Item index 0\r\n\t// ~ Re-measure item height ~\r\n\t// Previous height 917\r\n\t// New height 1064.453125\r\n\t// ~ Item height has changed ~\r\n\t//\r\n\t// An alternative solution would be demanding the `itemComponent` to\r\n\t// accept a `ref` and then measuring the corresponding DOM element height\r\n\t// directly using the `ref`-ed DOM element rather than searching for that\r\n\t// DOM element in the `ItemsContainer`.\r\n\t// So if `useInsertionEffect()` gets removed from React in some hypothetical future,\r\n\t// it could be replaced with using `ref`s on `ItemComponent`s to measure the DOM element heights.\r\n\t//\r\n\tuseInsertionEffectDontMountTwiceInStrictMode(() => {\r\n\t\t// Update the actual `VirtualScroller` state right before the DOM changes\r\n\t\t// are going to be applied for the requested state update.\r\n\t\t//\r\n\t\t// This hook will run right before `useLayoutEffect()`.\r\n\t\t//\r\n\t\t// It doesn't make any difference which one of the two hooks to use to update\r\n\t\t// the actual `VirtualScroller` state in this scenario because the two hooks\r\n\t\t// run synchronously one right after another (insertion effect → DOM update → layout effect)\r\n\t\t// without any free space for any `VirtualScroller` code (like the scroll event handler)\r\n\t\t// to squeeze in and run in-between them, so the `VirtualScroller`'s `state`\r\n\t\t// is always gonna stay consistent with what's currently rendered on screen\r\n\t\t// from the `VirtualScroler`'s point of view, and the short transition period\r\n\t\t// it simply doesn't see because it doesn't \"wake up\" during that period.\r\n\t\t//\r\n\t\t// Updating the actual `VirtualScroller` state right before `useLayoutEffect()`\r\n\t\t// fixes the bug when an `itemComponent` calls `onHeightDidChange()` in its own\r\n\t\t// `useLayoutEffect()` which would run before this `useLayoutEffect()`\r\n\t\t// because children's effects run before parent's.\r\n\t\t//\r\n\t\t// This hook doesn't do anything at the initial render.\r\n\t\t//\r\n\t\tif (isDebug()) {\r\n\t\t\tlog('React: ~ The requested state is about to be applied in DOM. Setting it as the `VirtualScroller` state. ~')\r\n\t\t\tlog(getStateSnapshot(_newState))\r\n\t\t}\r\n\t\tsetState(_newState)\r\n\t}, [_newState])\r\n\r\n\tuseLayoutEffectDontMountTwiceInStrictMode(() => {\r\n\t\t// Call `onRender()` right after a requested state update has been applied,\r\n\t\t// and also right after the initial render.\r\n\t\tonRender()\r\n\t}, [_newState])\r\n\r\n\treturn {\r\n\t\t// This is the state the component should render.\r\n\t\tstateToRender: _newState,\r\n\r\n\t\t// Returns the current state of the `VirtualScroller`.\r\n\t\t// This function is used in the `VirtualScroller` itself\r\n\t\t// because the `state` is managed outside of it.\r\n\t\tgetState,\r\n\r\n\t\t// Requests a state update.\r\n\t\tsetState: _setNewState\r\n\t}\r\n}"],"mappings":";;;;;;;;;;;;AAAA,OAAOA,GAAP,IAAcC,OAAd,QAA6B,qBAA7B;AACA,OAAOC,gBAAP,MAA6B,gCAA7B;AAEA,SAASC,MAAT,EAAiBC,WAAjB,QAAoC,OAApC;AACA,OAAOC,kBAAP,MAA+B,yBAA/B;AACA,OAAOC,4CAAP,MAAyD,mDAAzD;AACA,OAAOC,yCAAP,MAAsD,gDAAtD,C,CAEA;;AACA,eAAe,SAASC,SAAT,OAIZ;EAAA,IAHFC,YAGE,QAHFA,YAGE;EAAA,IAFFC,QAEE,QAFFA,QAEE;EAAA,IADFC,aACE,QADFA,aACE;;EACF;EACA;EACA;EACA;EACA;EACA,0BAAkCN,kBAAkB,CAACI,YAAD,CAApD;EAAA;EAAA,IAAOG,SAAP;EAAA,IAAkBC,YAAlB,2BANE,CAQF;EACA;;;EACA,IAAMC,KAAK,GAAGX,MAAM,CAACM,YAAD,CAApB;EAEA,IAAMM,QAAQ,GAAGX,WAAW,CAAC,YAAM;IAClC,OAAOU,KAAK,CAACE,OAAb;EACA,CAF2B,EAEzB,EAFyB,CAA5B;EAIA,IAAMC,QAAQ,GAAGb,WAAW,CAAC,UAACc,QAAD,EAAc;IAC1CJ,KAAK,CAACE,OAAN,GAAgBE,QAAhB;EACA,CAF2B,EAEzB,EAFyB,CAA5B,CAhBE,CAoBF;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EACAZ,4CAA4C,CAAC,YAAM;IAClD;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,IAAIL,OAAO,EAAX,EAAe;MACdD,GAAG,CAAC,0GAAD,CAAH;MACAA,GAAG,CAACE,gBAAgB,CAACU,SAAD,CAAjB,CAAH;IACA;;IACDK,QAAQ,CAACL,SAAD,CAAR;EACA,CA3B2C,EA2BzC,CAACA,SAAD,CA3ByC,CAA5C;EA6BAL,yCAAyC,CAAC,YAAM;IAC/C;IACA;IACAG,QAAQ;EACR,CAJwC,EAItC,CAACE,SAAD,CAJsC,CAAzC;EAMA,OAAO;IACN;IACAO,aAAa,EAAEP,SAFT;IAIN;IACA;IACA;IACAG,QAAQ,EAARA,QAPM;IASN;IACAE,QAAQ,EAAEJ;EAVJ,CAAP;AAYA"}
@@ -0,0 +1,51 @@
1
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
2
+
3
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
+
5
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6
+
7
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
8
+
9
+ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
10
+
11
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
12
+
13
+ import { useRef, useState, useCallback } from 'react'; // This hook fixes any weird intermediate inconsistent/invalid/stale state values.
14
+ // https://github.com/facebook/react/issues/25023#issuecomment-1480463544
15
+
16
+ export default function useStateNoStaleBug(initialState) {
17
+ // const latestValidState = useRef(initialState)
18
+ var latestWrittenState = useRef(initialState);
19
+
20
+ var _useState = useState(initialState),
21
+ _useState2 = _slicedToArray(_useState, 2),
22
+ _state = _useState2[0],
23
+ _setState = _useState2[1]; // Instead of dealing with a potentially out-of-sync (stale) state value,
24
+ // simply use the correct latest one.
25
+
26
+
27
+ var state = latestWrittenState.current;
28
+ /*
29
+ let state
30
+ if (_state === latestWrittenState.current) {
31
+ state = _state
32
+ latestValidState.current = _state
33
+ } else {
34
+ // React bug detected: an out-of-sync (stale) state value received.
35
+ // Ignore the out-of-sync (stale) state value.
36
+ state = latestValidState.current
37
+ }
38
+ */
39
+
40
+ var setState = useCallback(function (newState) {
41
+ if (typeof newState === 'function') {
42
+ throw new Error('Function argument of `setState()` function is not supported by this hook');
43
+ }
44
+
45
+ latestWrittenState.current = newState;
46
+
47
+ _setState(newState);
48
+ }, []);
49
+ return [state, setState];
50
+ }
51
+ //# sourceMappingURL=useStateNoStaleBug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStateNoStaleBug.js","names":["useRef","useState","useCallback","useStateNoStaleBug","initialState","latestWrittenState","_state","_setState","state","current","setState","newState","Error"],"sources":["../../source/react/useStateNoStaleBug.js"],"sourcesContent":["import { useRef, useState, useCallback } from 'react'\r\n\r\n// This hook fixes any weird intermediate inconsistent/invalid/stale state values.\r\n// https://github.com/facebook/react/issues/25023#issuecomment-1480463544\r\nexport default function useStateNoStaleBug(initialState) {\r\n // const latestValidState = useRef(initialState)\r\n const latestWrittenState = useRef(initialState)\r\n const [_state, _setState] = useState(initialState)\r\n\r\n // Instead of dealing with a potentially out-of-sync (stale) state value,\r\n // simply use the correct latest one.\r\n const state = latestWrittenState.current\r\n\r\n /*\r\n let state\r\n if (_state === latestWrittenState.current) {\r\n state = _state\r\n latestValidState.current = _state\r\n } else {\r\n // React bug detected: an out-of-sync (stale) state value received.\r\n // Ignore the out-of-sync (stale) state value.\r\n state = latestValidState.current\r\n }\r\n */\r\n\r\n const setState = useCallback((newState) => {\r\n if (typeof newState === 'function') {\r\n throw new Error('Function argument of `setState()` function is not supported by this hook')\r\n }\r\n latestWrittenState.current = newState\r\n _setState(newState)\r\n }, [])\r\n\r\n return [state, setState]\r\n}"],"mappings":";;;;;;;;;;;;AAAA,SAASA,MAAT,EAAiBC,QAAjB,EAA2BC,WAA3B,QAA8C,OAA9C,C,CAEA;AACA;;AACA,eAAe,SAASC,kBAAT,CAA4BC,YAA5B,EAA0C;EACvD;EACA,IAAMC,kBAAkB,GAAGL,MAAM,CAACI,YAAD,CAAjC;;EACA,gBAA4BH,QAAQ,CAACG,YAAD,CAApC;EAAA;EAAA,IAAOE,MAAP;EAAA,IAAeC,SAAf,iBAHuD,CAKvD;EACA;;;EACA,IAAMC,KAAK,GAAGH,kBAAkB,CAACI,OAAjC;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;EAEE,IAAMC,QAAQ,GAAGR,WAAW,CAAC,UAACS,QAAD,EAAc;IACzC,IAAI,OAAOA,QAAP,KAAoB,UAAxB,EAAoC;MAClC,MAAM,IAAIC,KAAJ,CAAU,0EAAV,CAAN;IACD;;IACDP,kBAAkB,CAACI,OAAnB,GAA6BE,QAA7B;;IACAJ,SAAS,CAACI,QAAD,CAAT;EACD,CAN2B,EAMzB,EANyB,CAA5B;EAQA,OAAO,CAACH,KAAD,EAAQE,QAAR,CAAP;AACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "virtual-scroller",
3
- "version": "1.12.2",
3
+ "version": "1.12.4",
4
4
  "description": "A component for efficiently rendering large lists of variable height items",
5
5
  "main": "index.cjs",
6
6
  "module": "index.js",
package/source/Layout.js CHANGED
@@ -54,7 +54,7 @@ export default class Layout {
54
54
  return getValue()
55
55
  } catch (error) {
56
56
  if (error instanceof ScrollableContainerNotReadyError) {
57
- log('Couldn\'t calculate', name, 'before scrollable container is ready. Default to', defaultValue);
57
+ log(`Scrollable container size is not known at this point, so "${name}" can't be calculated yet. Default to`, defaultValue);
58
58
  return defaultValue
59
59
  } else {
60
60
  throw error
@@ -356,14 +356,12 @@ export default class Layout {
356
356
  */
357
357
  getShownItemIndexes({
358
358
  itemsCount,
359
- visibleAreaTop,
360
- visibleAreaBottom
359
+ visibleAreaInsideTheList
361
360
  }) {
362
361
  let indexes = this._getShownItemIndex({
363
362
  itemsCount,
364
363
  fromIndex: 0,
365
- visibleAreaTop,
366
- visibleAreaBottom,
364
+ visibleAreaInsideTheList,
367
365
  findFirstShownItemIndex: true
368
366
  })
369
367
 
@@ -381,8 +379,7 @@ export default class Layout {
381
379
  itemsCount,
382
380
  fromIndex: firstShownItemIndex,
383
381
  beforeItemsHeight,
384
- visibleAreaTop,
385
- visibleAreaBottom,
382
+ visibleAreaInsideTheList,
386
383
  findLastShownItemIndex: true
387
384
  })
388
385
 
@@ -406,8 +403,7 @@ export default class Layout {
406
403
  const {
407
404
  beforeResize,
408
405
  itemsCount,
409
- visibleAreaTop,
410
- visibleAreaBottom,
406
+ visibleAreaInsideTheList,
411
407
  findFirstShownItemIndex,
412
408
  findLastShownItemIndex,
413
409
  // backwards
@@ -441,7 +437,8 @@ export default class Layout {
441
437
  // If "previously calculated layout" would be used then it would first find
442
438
  // `firstShownItemIndex` and then find `lastShownItemIndex` as part of two
443
439
  // separate calls of this function, each with or without `backwards` flag,
444
- // depending on whether `visibleAreaTop` and `visibleAreBottom` have shifted up or down.
440
+ // depending on whether `visibleAreaInsideTheList.top` and `visibleAreaInsideTheList.top`
441
+ // have shifted up or down.
445
442
 
446
443
  let firstShownItemIndex
447
444
  let lastShownItemIndex
@@ -525,7 +522,7 @@ export default class Layout {
525
522
  itemsCount,
526
523
  firstShownItemIndex: findLastShownItemIndex ? fromIndex : undefined,
527
524
  indexOfTheFirstItemInTheRow: currentRowFirstItemIndex,
528
- nonMeasuredAreaHeight: (visibleAreaBottom + this.getPrerenderMargin()) - beforeItemsHeight
525
+ nonMeasuredAreaHeight: (visibleAreaInsideTheList.bottom + this.getPrerenderMargin()) - beforeItemsHeight
529
526
  })
530
527
  }
531
528
 
@@ -537,8 +534,8 @@ export default class Layout {
537
534
 
538
535
  const itemsHeightFromFirstRowToThisRow = beforeItemsHeight + currentRowHeight
539
536
 
540
- const rowStepsIntoVisibleAreaTop = itemsHeightFromFirstRowToThisRow > visibleAreaTop - this.getPrerenderMargin()
541
- const rowStepsOutOfVisibleAreaBottomOrIsAtTheBorder = itemsHeightFromFirstRowToThisRow + verticalSpacingAfterCurrentRow >= visibleAreaBottom + this.getPrerenderMargin()
537
+ const rowStepsIntoVisibleAreaTop = itemsHeightFromFirstRowToThisRow > visibleAreaInsideTheList.top - this.getPrerenderMargin()
538
+ const rowStepsOutOfVisibleAreaBottomOrIsAtTheBorder = itemsHeightFromFirstRowToThisRow + verticalSpacingAfterCurrentRow >= visibleAreaInsideTheList.bottom + this.getPrerenderMargin()
542
539
 
543
540
  // if (backwards) {
544
541
  // if (findFirstShownItemIndex) {
@@ -31,8 +31,10 @@ describe('Layout', function() {
31
31
  // Initial render.
32
32
  layout.getShownItemIndexes({
33
33
  itemsCount: items.length,
34
- visibleAreaTop: 0,
35
- visibleAreaBottom: SCREEN_HEIGHT
34
+ visibleAreaInsideTheList: {
35
+ top: 0,
36
+ bottom: SCREEN_HEIGHT
37
+ }
36
38
  }).should.deep.equal({
37
39
  firstShownItemIndex: 0,
38
40
  lastShownItemIndex: 2
@@ -41,8 +43,10 @@ describe('Layout', function() {
41
43
  // The first item is almost hidden.
42
44
  layout.getShownItemIndexes({
43
45
  itemsCount: items.length,
44
- visibleAreaTop: SCREEN_HEIGHT + ITEM_HEIGHT - 1,
45
- visibleAreaBottom: (SCREEN_HEIGHT + ITEM_HEIGHT - 1) + SCREEN_HEIGHT
46
+ visibleAreaInsideTheList: {
47
+ top: SCREEN_HEIGHT + ITEM_HEIGHT - 1,
48
+ bottom: (SCREEN_HEIGHT + ITEM_HEIGHT - 1) + SCREEN_HEIGHT
49
+ }
46
50
  }).should.deep.equal({
47
51
  firstShownItemIndex: 0,
48
52
  lastShownItemIndex: 4
@@ -51,8 +55,10 @@ describe('Layout', function() {
51
55
  // The first item is hidden.
52
56
  layout.getShownItemIndexes({
53
57
  itemsCount: items.length,
54
- visibleAreaTop: SCREEN_HEIGHT + ITEM_HEIGHT,
55
- visibleAreaBottom: (SCREEN_HEIGHT + ITEM_HEIGHT) + SCREEN_HEIGHT
58
+ visibleAreaInsideTheList: {
59
+ top: SCREEN_HEIGHT + ITEM_HEIGHT,
60
+ bottom: (SCREEN_HEIGHT + ITEM_HEIGHT) + SCREEN_HEIGHT
61
+ }
56
62
  }).should.deep.equal({
57
63
  firstShownItemIndex: 1,
58
64
  lastShownItemIndex: 4
@@ -61,8 +67,10 @@ describe('Layout', function() {
61
67
  // A new item at the bottom is almost visible.
62
68
  layout.getShownItemIndexes({
63
69
  itemsCount: items.length,
64
- visibleAreaTop: (ITEM_HEIGHT + VERTICAL_SPACING) * 5 - SCREEN_HEIGHT * 2,
65
- visibleAreaBottom: (ITEM_HEIGHT + VERTICAL_SPACING) * 5 - SCREEN_HEIGHT
70
+ visibleAreaInsideTheList: {
71
+ top: (ITEM_HEIGHT + VERTICAL_SPACING) * 5 - SCREEN_HEIGHT * 2,
72
+ bottom: (ITEM_HEIGHT + VERTICAL_SPACING) * 5 - SCREEN_HEIGHT
73
+ }
66
74
  }).should.deep.equal({
67
75
  firstShownItemIndex: 1,
68
76
  lastShownItemIndex: 4
@@ -71,8 +79,10 @@ describe('Layout', function() {
71
79
  // A new item at the bottom is visible.
72
80
  layout.getShownItemIndexes({
73
81
  itemsCount: items.length,
74
- visibleAreaTop: (ITEM_HEIGHT + VERTICAL_SPACING) * 5 + 1 - SCREEN_HEIGHT * 2,
75
- visibleAreaBottom: (ITEM_HEIGHT + VERTICAL_SPACING) * 5 + 1 - SCREEN_HEIGHT
82
+ visibleAreaInsideTheList: {
83
+ top: (ITEM_HEIGHT + VERTICAL_SPACING) * 5 + 1 - SCREEN_HEIGHT * 2,
84
+ bottom: (ITEM_HEIGHT + VERTICAL_SPACING) * 5 + 1 - SCREEN_HEIGHT
85
+ }
76
86
  }).should.deep.equal({
77
87
  firstShownItemIndex: 1,
78
88
  lastShownItemIndex: 5
package/source/Scroll.js CHANGED
@@ -42,6 +42,7 @@ export default class Scroll {
42
42
  start() {
43
43
  if (this.initialScrollPosition !== undefined) {
44
44
  this.scrollToY(this.initialScrollPosition)
45
+ // Don't restore this scroll position on restart.
45
46
  this.initialScrollPosition = undefined
46
47
  }
47
48
  if (this.onScrollPositionChange) {
@@ -1,7 +1,7 @@
1
1
  import debounce from './utility/debounce.js'
2
2
  import log from './utility/debug.js'
3
3
 
4
- export default class Resize {
4
+ export default class ScrollableContainerResizeHandler {
5
5
  constructor({
6
6
  bypass,
7
7
  getWidth,
@@ -6,7 +6,7 @@ import {
6
6
  import DOMEngine from './DOM/Engine.js'
7
7
 
8
8
  import Layout, { LAYOUT_REASON } from './Layout.js'
9
- import Resize from './Resize.js'
9
+ import ScrollableContainerResizeHandler from './ScrollableContainerResizeHandler.js'
10
10
  import BeforeResize from './BeforeResize.js'
11
11
  import Scroll from './Scroll.js'
12
12
  import ListHeightMeasurement from './ListHeightMeasurement.js'
@@ -19,7 +19,7 @@ import createVerticalSpacingHelpers from './VirtualScroller.verticalSpacing.js'
19
19
  import createColumnsHelpers from './VirtualScroller.columns.js'
20
20
  import createLayoutHelpers from './VirtualScroller.layout.js'
21
21
  import createOnRenderHelpers from './VirtualScroller.onRender.js'
22
- import createResizeHelpers from './VirtualScroller.resize.js'
22
+ import createScrollableContainerResizeHelpers from './VirtualScroller.onContainerResize.js'
23
23
  import createItemsHelpers from './VirtualScroller.items.js'
24
24
 
25
25
  /**
@@ -193,7 +193,7 @@ export default function VirtualScrollerConstructor(
193
193
 
194
194
  createLayoutHelpers.call(this)
195
195
  createOnRenderHelpers.call(this)
196
- createResizeHelpers.call(this)
196
+ createScrollableContainerResizeHelpers.call(this)
197
197
  createItemsHelpers.call(this)
198
198
 
199
199
  createHelpers.call(this, {
@@ -277,7 +277,7 @@ function createHelpers({
277
277
  getPreviouslyCalculatedLayout: () => this.previouslyCalculatedLayout
278
278
  })
279
279
 
280
- this.resize = new Resize({
280
+ this.scrollableContainerResizeHandler = new ScrollableContainerResizeHandler({
281
281
  bypass: this.bypass,
282
282
  getWidth: () => this.scrollableContainer.getWidth(),
283
283
  getHeight: () => this.scrollableContainer.getHeight(),
@@ -303,7 +303,7 @@ function createHelpers({
303
303
  }),
304
304
  onWidthChange: (prevWidth, newWidth) => {
305
305
  log('~ Scrollable container width changed from', prevWidth, 'to', newWidth, '~')
306
- this.onResize()
306
+ this.onContainerResize()
307
307
  }
308
308
  })
309
309
 
@@ -215,7 +215,7 @@ export default function() {
215
215
  // `this.newItemsWillBeRendered` is cleared in `onRender()`.
216
216
  //
217
217
  // The values in `this.newItemsWillBeRendered` are used, for example,
218
- // in `.onResize()` handler in order to not break state consistency when
218
+ // in `.onContainerResize()` handler in order to not break state consistency when
219
219
  // state updates are "asynchronous" (delayed) and there's a window resize event
220
220
  // in between calling `updateState()` below and that call actually being applied.
221
221
  //