useUniqueMemo.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
  2. import _createClass from "@babel/runtime/helpers/esm/createClass";
  3. import React from 'react';
  4. const BEAT_LIMIT = 1000 * 60 * 10;
  5. /**
  6. * A helper class to map keys to values.
  7. * It supports both primitive keys and object keys.
  8. */
  9. let ArrayKeyMap = /*#__PURE__*/function () {
  10. function ArrayKeyMap() {
  11. _classCallCheck(this, ArrayKeyMap);
  12. this.map = new Map();
  13. // Use WeakMap to avoid memory leak
  14. this.objectIDMap = new WeakMap();
  15. this.nextID = 0;
  16. this.lastAccessBeat = new Map();
  17. // We will clean up the cache when reach the limit
  18. this.accessBeat = 0;
  19. }
  20. return _createClass(ArrayKeyMap, [{
  21. key: "set",
  22. value: function set(keys, value) {
  23. // New set will trigger clear
  24. this.clear();
  25. // Set logic
  26. const compositeKey = this.getCompositeKey(keys);
  27. this.map.set(compositeKey, value);
  28. this.lastAccessBeat.set(compositeKey, Date.now());
  29. }
  30. }, {
  31. key: "get",
  32. value: function get(keys) {
  33. const compositeKey = this.getCompositeKey(keys);
  34. const cache = this.map.get(compositeKey);
  35. this.lastAccessBeat.set(compositeKey, Date.now());
  36. this.accessBeat += 1;
  37. return cache;
  38. }
  39. }, {
  40. key: "getCompositeKey",
  41. value: function getCompositeKey(keys) {
  42. const ids = keys.map(key => {
  43. if (key && typeof key === 'object') {
  44. return `obj_${this.getObjectID(key)}`;
  45. }
  46. return `${typeof key}_${key}`;
  47. });
  48. return ids.join('|');
  49. }
  50. }, {
  51. key: "getObjectID",
  52. value: function getObjectID(obj) {
  53. if (this.objectIDMap.has(obj)) {
  54. return this.objectIDMap.get(obj);
  55. }
  56. const id = this.nextID;
  57. this.objectIDMap.set(obj, id);
  58. this.nextID += 1;
  59. return id;
  60. }
  61. }, {
  62. key: "clear",
  63. value: function clear() {
  64. if (this.accessBeat > 10000) {
  65. const now = Date.now();
  66. this.lastAccessBeat.forEach((beat, key) => {
  67. if (now - beat > BEAT_LIMIT) {
  68. this.map.delete(key);
  69. this.lastAccessBeat.delete(key);
  70. }
  71. });
  72. this.accessBeat = 0;
  73. }
  74. }
  75. }]);
  76. }();
  77. const uniqueMap = new ArrayKeyMap();
  78. /**
  79. * Like `useMemo`, but this hook result will be shared across all instances.
  80. */
  81. function useUniqueMemo(memoFn, deps) {
  82. return React.useMemo(() => {
  83. const cachedValue = uniqueMap.get(deps);
  84. if (cachedValue) {
  85. return cachedValue;
  86. }
  87. const newValue = memoFn();
  88. uniqueMap.set(deps, newValue);
  89. return newValue;
  90. }, deps);
  91. }
  92. export default useUniqueMemo;