When using functions as components you have the ability to use the useMediaQuery
hook from material-ui. However it no where shows you how to use this hook inside a class.
So I did some research and found out you can use it in a class by doing this:
import React from 'react';
import useMediaQuery from '@material-ui/core/useMediaQuery';
const withMediaQuery = (...args) => Component => props => {
const mediaQuery = useMediaQuery(...args);
return <Component mediaQuery={mediaQuery} {...props} />;
};
export default withMediaQuery;
However when adding it to the class like this:
export default withStyles(styles)(withMediaQuery(Main));
It gives me this error:
index.js:1 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
I really need to use the media query because some variables are dependent on them. This is the render method of the class which I would like to use the media query for.
render() {
const { classes, children } = this.props;
const isDesktop = useMediaQuery(theme => theme.breakpoints.up('lg'), {
defaultMatches: true,
});
const shouldOpenSidebar = isDesktop ? true : this.state.openSidebar;
return (
<div
className={cc({
[classes.root]: true,
[classes.shiftContent]: isDesktop,
})}>
<Topbar
onSidebarOpen={this.handleSidebarOpen}
/>
<Sidebar
onClose={this.handleSidebarClose}
open={shouldOpenSidebar}
variant={isDesktop ? 'persistent' : 'temporary'}
/>
<main className={classes.content}>
{children}
</main>
</div>
);
}
I've already tried wrapping the component, but then I wouldn't be able to use the variables
You're not supplying the args
needed for useMediaQuery
, so Main
is passed as the args
, and a function that expects the component is returned. When React tried to render (call the function), the return value is another function, which is not value as a react child.
Call the function - withMediaQuery
and pass it the media queries, and then pass Main
to the returned function.
Example:
export default withStyles(styles)(withMediaQuery('(min-width:600px)')(Main));
Instead of limiting yourself to only one media query a better withMediaQuery HOC could be
import React from 'react'
import useMediaQuery from '@material-ui/core/useMediaQuery'
export const withMediaQuery = (queries = []) => Component => props => {
const mediaProps = {}
queries.forEach(q => {
mediaProps[q[0]] = useMediaQuery(q[1])
})
return <Component {...mediaProps} {...props} />
}
This would allow you to pass in multiple queries as an array of arrays. Each entry would be a prop name and then the query.
export default withStyles(styles)(withMediaQuery([
['isDesktop', theme => theme.breakpoints.up('lg'), {
defaultMatches: true
}]
]))
In your component you could then request the prop names directly in render
render() {
const { classes, children, IsDesktop = false } = this.props;
const shouldOpenSidebar = IsDesktop ? true : this.state.openSidebar;
return (
<div
className={cc({
[classes.root]: true,
[classes.shiftContent]: isDesktop,
})}>
<Topbar
onSidebarOpen={this.handleSidebarOpen}
/>
<Sidebar
onClose={this.handleSidebarClose}
open={shouldOpenSidebar}
variant={isDesktop ? 'persistent' : 'temporary'}
/>
<main className={classes.content}>
{children}
</main>
</div>
);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.