Skip to content

Instantly share code, notes, and snippets.

@PaquitoSoft
Created December 10, 2020 12:28
Show Gist options
  • Save PaquitoSoft/f28cd59dc2cd2474c6c27014af71260b to your computer and use it in GitHub Desktop.
Save PaquitoSoft/f28cd59dc2cd2474c6c27014af71260b to your computer and use it in GitHub Desktop.
import React, {
useContext,
useEffect,
useRef,
useState,
lazy
} from 'react';
import PropTypes from 'prop-types';
const BREAKPOINTS = [
{ name: 'xs', size: 0 },
{ name: 'sm', size: 640 },
{ name: 'md', size: 768 },
{ name: 'lg', size: 1024 },
{ name: 'xl', size: 1280 },
{ name: 'xxl', size: 1536 }
];
const ResponsiveContext = React.createContext({
breakpoints: {},
currentBreakpoint: {},
selectResponsiveComponent: (components) => null
});
function findResponsiveComponent(components, breakpoints, currentBreakpoint) {
const breakPointIndex = breakpoints.findIndex(bp => bp.name === currentBreakpoint.name) || 0;
for (let index = breakPointIndex; index >= 0; index--) {
if (components[breakpoints[index].name]) {
return components[breakpoints[index].name];
}
}
const error = new Error('Responsive Component not found');
error.meta = {
providedComponents: components,
currentBreakpoint: currentBreakpoint.name
};
throw error;
}
function calculateBreakpoint(reversedBreakpoints) {
for (let breakpoint of reversedBreakpoints) {
if (window.matchMedia(`(min-width: ${breakpoint.size}px)`).matches) {
return breakpoint;
}
}
}
function ResponsiveProvider({ breakpoints = BREAKPOINTS, children }) {
const reversedBreakPoints = useRef([...breakpoints].reverse());
const [currentBreakpoint, setCurrentBreakpoint] = useState(calculateBreakpoint(reversedBreakPoints.current) || breakpoints[0]);
const onResize = () => {
const newBreakpoint = calculateBreakpoint(reversedBreakPoints.current) || breakpoints[0];
setCurrentBreakpoint((prevBreakpoint => {
return prevBreakpoint.name !== newBreakpoint.name ? newBreakpoint : prevBreakpoint;
}));
};
useEffect(() => {
onResize();
window.addEventListener('resize', onResize, { passive: true });
return () => window.removeEventListener('resize', onResize);
}, []);
return (
<ResponsiveContext.Provider
value={{
breakpoints,
currentBreakpoint,
selectResponsiveComponent: (components) => lazy(findResponsiveComponent(components, breakpoints, currentBreakpoint))
}}
>
{children}
</ResponsiveContext.Provider>
)
}
ResponsiveProvider.propTypes = {
breakpoints: PropTypes.shape({
xs: PropTypes.number,
sm: PropTypes.number,
lg: PropTypes.number,
xl: PropTypes.number,
xxl: PropTypes.number,
}),
children: PropTypes.node.isRequired
};
const useResponsive = () => useContext(ResponsiveContext);
export {
ResponsiveProvider,
useResponsive
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment