UNPKG

@react-hookz/web

Version:

React hooks done right, for browser and SSR.

83 lines (82 loc) 2.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useMediaQuery = void 0; var react_1 = require("react"); var __1 = require(".."); var const_1 = require("../util/const"); var queriesMap = new Map(); var querySubscribe = function (query, setState) { var entry = queriesMap.get(query); if (!entry) { var mql_1 = matchMedia(query); var dispatchers_1 = new Set(); var listener = function () { dispatchers_1.forEach(function (d) { return d(mql_1.matches); }); }; if (mql_1.addEventListener) mql_1.addEventListener('change', listener, { passive: true }); else mql_1.addListener(listener); entry = { mql: mql_1, dispatchers: dispatchers_1, listener: listener, }; queriesMap.set(query, entry); } entry.dispatchers.add(setState); setState(entry.mql.matches, true); }; var queryUnsubscribe = function (query, setState) { var entry = queriesMap.get(query); // else path is impossible to test in normal situation /* istanbul ignore else */ if (entry) { var mql = entry.mql, dispatchers = entry.dispatchers, listener = entry.listener; dispatchers.delete(setState); if (!dispatchers.size) { queriesMap.delete(query); if (mql.removeEventListener) mql.removeEventListener('change', listener); else mql.removeListener(listener); } } }; /** * Tracks the state of CSS media query. * * Defaults to false in SSR environments * * @param query CSS media query to track. * @param matchOnMount whether hook state should be fetched during effects stage instead of * synchronous fetch. Set this parameter to `true` for SSR use-cases. */ function useMediaQuery(query, matchOnMount) { var rerender = (0, __1.useRerender)(); var previousQuery = (0, __1.usePrevious)(query); var state = (0, react_1.useRef)(); var setState = (0, react_1.useCallback)(function (matches, initial) { if (state.current !== matches) { state.current = matches; if (!initial || matchOnMount) rerender(); } }, // eslint-disable-next-line react-hooks/exhaustive-deps [matchOnMount]); // do synchronous subscription only for case we are in browser and mount match required if (!matchOnMount && const_1.isBrowser && previousQuery !== query) { querySubscribe(query, setState); } // otherwise, match should happen in effect stage (0, react_1.useEffect)(function () { if (matchOnMount) { querySubscribe(query, setState); } return function () { return queryUnsubscribe(query, setState); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [query]); return state.current; } exports.useMediaQuery = useMediaQuery;