A dead simple React Higher Order Component (HOC) that uses context for matching media queries
npm install react-media-query-hocA dead simple React Higher Order Component (HOC) that uses context for matching media queries.
MediaQuery components all over your code baseMediaQueryProvider that listens to media events you wish to configure)Via NPM:
``bash`
npm install react-media-query-hoc --save
Via Yarn:
`bash`
yarn add react-media-query-hoc
This library is designed so that you have 1 MediaQueryProvider parent and 1-many child components wrapped with withMedia HOC
This component will listen to media events you want to configure, it should be used once as a parent component.
Usage:
`javascript
import { MediaQueryProvider } from 'react-media-query-hoc';
const App = (props) => {
return (
);
};
export default App;
`
By providing no queries prop to the MediaQueryProvider component, it will default to these media queries
But you can provide different media queries for your use case using the queries prop, eg:
`javascript
const App = (props) => {
const customQueries = {
verySmall: 'screen and (max-width: 300px)',
someOtherMediaQuery: 'screen and (min-width: 301px)',
};
return (
);
};
`
This is a HOC to provide media match props to your component.
Usage:
`javascript
import { withMedia } from 'react-media-query-hoc';
const MyComponent = ({ media, ...props}) => {
if (media.tablet || media.mobile) {
return (
return (
export const BaseMyComponent = MyComponent;
export default withMedia(MyComponent);
`
Components wrapped by withMedia() won't work with React's usual ref mechanism, because the ref supplied will be for withMedia rather than the wrapped component. Therefore a prop, wrappedRef provides the same function. Note: this means the wrapped component can not be a stateless function.
hook. It has a default value of {}, present when the component that consumes the context is not wrapped with MediaQueryProvider.`javascript
import { MediaContext } from 'react-media-query-hoc';
import { useContext } from 'react';const MyComponent = (props) => {
const media = useContext(MediaContext);
if(media.tablet || media.mobile) {
return (
Mobile and Tablet View
)
} return (
Other View
);
};export default MyComponent;
// default value
ReactDOM.render( ); // Renders 'Other View';
`$3
You can pass in media features from your server, all supported values can be found here.
Usage (matches mobile screen during SSR):
`javascript
const App = (props) => {
const values = {
width: 300,
type: 'screen',
}; return (
);
};
`#### React 16 ReactDOM.hydrate
It's very important to realise a server client mismatch is dangerous when using hydrate in React 16, ReactDOM.hydrate
can cause very strange html on the client if there is a mismatch.
To mitigate this we use the two-pass rendering technique mentioned in the React docs.
We render on the client in the first pass using
values with css-mediaquery used on the server, then we use the browsers native window.matchMedia
to get it's actual dimensions and render again if it causes different query results. This means there should be no React
server/client mismatch warning in your console and you can safely use hydrate. As a result of above, if you are server side rendering and using ReactDOM.hydrate you must supply MediaQueryProvider a values prop.Browser Support
The oldest browser we support is IE11,
if you want to support even older browsers please make sure you are using a polyfill for Map such as
babel-polyfill.Testing Components
Because the media queries and context are abstracted out you can easily test components with or without the
withMedia HOC, just ensure you export your component base without the HOC as well, eg:`javascript
export const BaseMyComponent = MyComponent;
export default withMedia(MyComponent);
`Then in your React tests you can import like:
`javascript
import { BaseMyComponent } from 'location_of_my_component';
``Big thanks to the maintainers of these repos
- https://github.com/jxnblk/react-media-context
- https://github.com/contra/react-responsive
Both libraries are a bit similar, but my original use case required the extra advantages listed in Why use this?