use-media.ts 1.3 KB

12345678910111213141516171819202122232425262728293031
  1. import React from "react";
  2. const useMedia = <T>(queries: string[], values: T[], defaultValue: T) => {
  3. // Array containing a media query list for each query
  4. const mediaQueryLists = queries.map((q) => window.matchMedia(q));
  5. // Function that gets value based on matching media query
  6. const getValue = () => {
  7. // Get index of first media query that matches
  8. const index = mediaQueryLists.findIndex((mql) => mql.matches);
  9. // Return related value or defaultValue if none
  10. return values?.[index] || defaultValue;
  11. };
  12. // State and setter for matched value
  13. const [value, setValue] = React.useState<T>(getValue)
  14. React.useEffect(
  15. () => {
  16. // Event listener callback
  17. // Note: By defining getValue outside of useEffect we ensure that it has ...
  18. // ... current values of hook args (as this hook callback is created once on mount).
  19. const handler = () => setValue(getValue)
  20. // Set a listener for each media query with above handler as callback.
  21. mediaQueryLists.forEach((mql) => mql.addListener(handler))
  22. // Remove listeners on cleanup
  23. return () => mediaQueryLists.forEach((mql) => mql.removeListener(handler))
  24. },
  25. [] // Empty array ensures effect is only run on mount and unmount
  26. )
  27. return value;
  28. };
  29. export default useMedia;