useCompactSelectOptionsCache.tsx 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. import {useCallback, useMemo, useRef} from 'react';
  2. import type {SelectKey, SelectOption} from 'sentry/components/compactSelect';
  3. type Option = SelectOption<SelectKey>;
  4. type OptionCache<T extends Option> = Map<SelectKey, T>;
  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<T extends Option>(
  20. options: T[]
  21. ): {
  22. clear: () => void;
  23. options: T[];
  24. } {
  25. const cache = useRef<OptionCache<T>>(new Map());
  26. const clearCache = useCallback(() => {
  27. cache.current.clear();
  28. }, []);
  29. const outgoingOptions = useMemo(() => {
  30. options.forEach(option => {
  31. cache.current.set(option.value, option);
  32. });
  33. return Array.from(cache.current.values()).sort(alphabeticalCompare);
  34. }, [options]);
  35. return {options: outgoingOptions, clear: clearCache};
  36. }
  37. type OptionComparator = (a: Option, b: Option) => number;
  38. const alphabeticalCompare: OptionComparator = (a, b) => {
  39. return a.value.toString().localeCompare(b.value.toString());
  40. };