The problem
Sometimes you want the current responsiveness interval in JavaScript.
Most attempts (and answers on StackOverflow) are placing an event listener on window.resize
and then use some custom logic (a switch
statement) to output the current interval.
Works, but not ideal.
Biggest problem is it runs on window.resize
, which fires tens of times per second while resizing, creating tiny freezes in page display, a clear sign the browser is struggling
The solution
A cleaner (and more performant) alternative is to use window.matchMedia(queryString)
.
It returns an instance of MediaQueryList
.
Binding a callback on this instance's change
event ensures the callback will only be called when the media query starts/stops matching.
const [isSm, setIsSm] = useState(false)
useEffect(() => {
const queryList = window.matchMedia(
'(min-width: 640px) and (max-width: 767.9px)'
)
queryList.addEventListener('change', ({ matches }) =>
setIsSm(matches)
)
}, [])
The other cool thing about it is you don't need to clean up the bound event. If you delete the MediaQueryList
itself, the listener is garbage collected, so no listeners are left behind on <body>
or window
object after the component unmounted.
Wrap up
Having seen this question answered less than ideal a few times, I decided to write a tiny plugin (react-responsiveness) which takes an optional config object (interval: min
dictionary - defaults to Bootstrap 5's breakpoints) and returns a context provider and a hook.
I added presets for commonly used frameworks: Bootstrap_3
, Bootstrap_4
, Bootstrap_5
, Bulma
, Chakra
, Foundation
, Ionic
, Material_Design
, Materialize
, Material_UI
, Quasar
, Semantic_UI
, Skeleton
, Tailwind_CSS
, Vuetify
, Windi_CSS
.
Installation
yarn add react-responsiveness
Add the provider
import {
ResponsivenessProvider,
Presets,
} from "react-responsiveness";
function App() {
// ...
}
const WithResponsiveness = () => (
<ResponsivenessProvider breakpoints={Presets.Tailwind_CSS}>
<App />
</ResponsivenessProvider>
);
export default WithResponsiveness;
Use in components
The hook exposes isMin
, isMax
and isOnly
helper methods, the currentInterval
and a more verbose matches
object, which can be all be used to show/hide things responsively:
import { useResponsiveness } from "react-responsiveness"
const { isMin, isMax, isOnly, currentInterval } =
useResponsiveness()
return (
<>
<div>Current interval {currentInterval}</div>
{isMin("md") && (
// @media (min-width: 768px)
<div>content...</div>
)}
{isMax("md") && (
// @media (max-width: 991.9px)
<div>content...</div>
)}
{isOnly("md") && (
// @media (min-width: 768px) and (max-width: 991.9px)
<div>content...</div>
)}
</>
)
Note: the interval names vary based on the preset or config you used.
Use with bespoke breakpoints
<ResponsivenessProvider
breakpoints={{
small: 0,
medium: 777,
large: 1234,
}}
>
// ...
</ResponsivenessProvider>
{isOnly('medium') && (
// @media (min-width: 777px) and (max-width: 1233.9px)
<div>content...</div>
)}
Demo
If you find it useful, let me know.
Cheers!
Top comments (0)