Skip to content

Instantly share code, notes, and snippets.

@codingwithchris
Last active April 27, 2020 22:14
Show Gist options
  • Save codingwithchris/851048a3a686cf846961779e88fc73ab to your computer and use it in GitHub Desktop.
Save codingwithchris/851048a3a686cf846961779e88fc73ab to your computer and use it in GitHub Desktop.
React Client-side Responsive Layout Component (with Context & Custom Hook)
// These are all the breakpoint sizes for use within your system.
export const mediaQuerySizes: AvailableBreakpoints = {
xs: 414,
s: 768,
m: 960,
l: 1040,
xl: 1440,
xxl: 1640,
};
// This variable returns an object containing all available media query wrappers for use within styled components
//
// Example Usage:
//
// ${breakpoints.s} {
// ...css rules
// }
//
export const breakpoints = Object.keys(mediaQuerySizes).reduce(
(accumulator, breakpoint) => ({
...accumulator,
[breakpoint]: `@media (min-width: ${
mediaQuerySizes[breakpoint as AvailableBreakpoint]
}px)`,
}),
{} as AvailableBreakpoints
);
export interface AvailableBreakpoints {
xs: number;
s: number;
m: number;
l: number;
xl: number;
xxl: number;
}
export type AvailableBreakpoint = keyof AvailableBreakpoints;
import * as React from 'react';
import { useViewport } from '@hooks';
import { mediaQuerySizes, AvailableBreakpoint } from '@tokens';
/**
*
* @param breakpoint
* @param mobileView
* @param desktopView
*/
export const ResponsiveLayout: React.FC<ResponsiveLayoutProps> = ({
breakpoint,
mobileView,
desktopView,
}) => {
const { width } = useViewport();
const selectedBreakpoint = mediaQuerySizes[breakpoint];
return width > selectedBreakpoint ? desktopView() : mobileView();
};
interface ResponsiveLayoutProps {
breakpoint: AvailableBreakpoint;
mobileView: () => React.ReactElement | null;
desktopView: () => React.ReactElement | null;
}
import * as React from 'react';
import { ViewportContext } from '@context';
export const useViewport = () => {
const { width, height } = React.useContext(ViewportContext);
return { width, height };
};
import * as React from 'react';
export const ViewportContext = React.createContext({} as ViewportProps);
export const ViewportProvider: React.FC = ({ children }) => {
const [width, setWidth] = React.useState(window.innerWidth);
const [height, setHeight] = React.useState(window.innerHeight);
const handleResize = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
};
React.useLayoutEffect(() => {
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return (
<ViewportContext.Provider value={{ width, height }}>
{children}
</ViewportContext.Provider>
);
};
interface ViewportProps {
width: number;
height: number;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment