useCompactSelectOptionsCache.tsx 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. import {useCallback, useMemo, useRef} from 'react';
  2. import type {SelectKey, SelectOption} from 'sentry/components/compactSelect';
  3. type Option = SelectOption<SelectKey>;
  4. type OptionCache = Map<SelectKey, Option>;
  5. /**
  6. * Cache designed for the `option` prop of a `CompactSelect`. Accepts
  7. * an array of `Option` objects. Returns a list of all `Option` objects
  8. * it has been passed since instantiation.
  9. *
  10. * Useful when passing a `CompactSelect` `options` that come from a server
  11. * response. With a cache, `CompactSelect` can:
  12. *
  13. * 1. Display an options dropdown even when new results are loading
  14. * 2. Shows options from 3 searches ago if the user changes their mind
  15. *
  16. * NOTE: The `clear` callback does not trigger a re-render. The cleared
  17. * cache is returned on next call of the hook.
  18. */
  19. export function useCompactSelectOptionsCache(options: Option[]): {
  20. clear: () => void;
  21. options: Option[];
  22. } {
  23. const cache = useRef<OptionCache>(new Map());
  24. const clearCache = useCallback(() => {
  25. cache.current.clear();
  26. }, []);
  27. const outgoingOptions = useMemo(() => {
  28. options.forEach(option => {
  29. cache.current.set(option.value, option);
  30. });
  31. return Array.from(cache.current.values()).sort(alphabeticalCompare);
  32. }, [options]);
  33. return {options: outgoingOptions, clear: clearCache};
  34. }
  35. type OptionComparator = (a: Option, b: Option) => number;
  36. const alphabeticalCompare: OptionComparator = (a, b) => {
  37. return a.value.toString().localeCompare(b.value.toString());
  38. };