UNPKG

styled-breakpoints

Version:

Simple and powerful css breakpoints for styled-components and emotion

78 lines (64 loc) 1.99 kB
// @ts-check const { useState, useLayoutEffect, useEffect } = require('react'); const IS_SERVER = typeof window === 'undefined'; const useIsomorphicLayoutEffect = IS_SERVER ? useEffect : useLayoutEffect; exports.useMediaQuery = useMediaQuery; /** * React hook for checking whether a CSS media query matches. * * Works both in the browser and in SSR: * — does not access `window` on the server * — allows setting an initial value to prevent hydration mismatch * * @param {string} query * CSS media query. Can be provided with or without the `@media` prefix. * * @param {Object} [options] * @param {boolean} [options.defaultValue=false] * Value used on the server and as a fallback. * * @param {boolean} [options.initializeWithValue=true] * If `true`, the initial state is computed immediately from the media query. * If `false`, `defaultValue` is used until the first effect runs. * * @returns {boolean} * `true` if the media query matches the current viewport. */ function useMediaQuery( query, { defaultValue = false, initializeWithValue = true } = {} ) { function getMatches() { if (IS_SERVER) return defaultValue; return window.matchMedia(normalizeQuery(query)).matches; } const [isMatch, setIsMatch] = useState(() => { if (initializeWithValue) { return getMatches(); } /* istanbul ignore next */ return defaultValue; }); function handleChange() { setIsMatch(getMatches()); } useIsomorphicLayoutEffect(() => { if (IS_SERVER) return; const mediaQueryList = window.matchMedia(normalizeQuery(query)); handleChange(); mediaQueryList.addEventListener('change', handleChange); // eslint-disable-next-line consistent-return return () => { mediaQueryList.removeEventListener('change', handleChange); }; }, [query]); return isMatch; } /** * * @param {string} query * @returns {string} */ function normalizeQuery(query) { return query.replace(/^@media\s*/, ''); }