@react-hookz/web
Version:
React hooks done right, for browser and SSR.
83 lines (82 loc) • 2.95 kB
JavaScript
;
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;