-
-
Save nicolas-zozol/4495dae3c0b7531b4a13cd2c2471a96f to your computer and use it in GitHub Desktop.
useSize: get responsives sizes inside TSX code with React
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This custom hook is used to get the size of the screen and creates | |
* a context to share the size with all the components. | |
*/ | |
import React, { FC, useEffect, useState } from 'react' | |
export const tabletSize = '634px' | |
export const desktopSize = '1206px' | |
const tabletOrSmallerMediaQuery = `(max-width: ${desktopSize})` | |
const mobileMediaQuery = `(max-width: ${tabletSize})` | |
const desktopMediaQuery = `(min-width: ${desktopSize})` | |
export function isTabletOrSmaller() { | |
return window.matchMedia(`(max-width: ${desktopSize})`).matches | |
} | |
export function isMobile() { | |
return window.matchMedia(`(max-width: ${tabletSize})`).matches | |
} | |
export function isDesktop() { | |
return window.matchMedia(`(min-width: ${desktopSize})`).matches | |
} | |
function debounce<F extends (...params: any[]) => void>(fn: F, delay: number) { | |
let timeoutID: number = 0 | |
return function (this: any, ...args: any[]) { | |
clearTimeout(timeoutID) | |
timeoutID = window.setTimeout(() => fn.apply(this, args), delay) | |
} as F | |
} | |
function setter(): ISizeContext { | |
return { | |
isTabletOrSmaller: isTabletOrSmaller(), | |
isMobile: isMobile(), | |
isDesktop: isDesktop(), | |
} | |
} | |
interface ISizeContext { | |
isTabletOrSmaller: boolean | |
isMobile: boolean | |
isDesktop: boolean | |
} | |
const initialState: ISizeContext = setter() | |
export const SizeContext = React.createContext<ISizeContext>(initialState) | |
export const SizeProvider: FC = ({ children }) => { | |
const [screenSize, setMyScreenSize] = useState<ISizeContext>(initialState) | |
const tabletOrSmallerMediaQueryMatcher = window.matchMedia( | |
tabletOrSmallerMediaQuery | |
) | |
const mobileMediaQueryMatcher = window.matchMedia(mobileMediaQuery) | |
const desktopMediaQueryMatcher = window.matchMedia(desktopMediaQuery) | |
const handler = debounce(function onChange() { | |
setMyScreenSize(setter()) | |
}, 300) | |
useEffect(() => { | |
tabletOrSmallerMediaQueryMatcher.addEventListener('change', handler) | |
mobileMediaQueryMatcher.addEventListener('change', handler) | |
desktopMediaQueryMatcher.addEventListener('change', handler) | |
// Remove listeners on cleanup | |
return () => { | |
tabletOrSmallerMediaQueryMatcher.removeEventListener('change', handler) | |
mobileMediaQueryMatcher.removeEventListener('change', handler) | |
desktopMediaQueryMatcher.removeEventListener('change', handler) | |
} | |
}, []) | |
return ( | |
<SizeContext.Provider | |
value={{ | |
isTabletOrSmaller: screenSize.isTabletOrSmaller, | |
isMobile: screenSize.isMobile, | |
isDesktop: screenSize.isDesktop, | |
}} | |
> | |
{children} | |
</SizeContext.Provider> | |
) | |
} | |
export const useSize = () => React.useContext(SizeContext) |
Another package do quite the same thing: https://github.com/ilyalesik/react-media-hook/blob/master/index.js
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
After adding the
SizeContext
at the right place, you can use it like that:It's useful to mix with other logic variables:
Have fun :)