material-ui
material-ui copied to clipboard
Support useMediaQuery without theme
useMediaQuery
logs a warning when called outside of a ThemeProvider
. But a library author may want to offer a fallback media query when no theme is defined.
- [x] This is not a v0.x issue.
- [x] I have searched the issues of this repository and believe that this is not a duplicate.
Expected Behavior 🤔
Calling this should not log any warning, because I can deal without the theme:
const isSmall = useMediaQuery(theme =>
theme ? theme.breakpoints.down('sm') : '(max-width:600px)'
);
But it does:
Warning: Material-UI: the `query` argument provided is invalid.
You are providing a function without a theme in the context.
One of the parent elements needs to use a ThemeProvider.
Why would I want to offer a fallback in case of missing theme? For unit tests. I want to be able to test my components without having to wrap them inside a ThemeProvider
.
Steps to Reproduce 🕹
https://codesandbox.io/s/interesting-hopper-q11wk
Your Environment 🌎
Tech | Version |
---|---|
Material-UI | v4.2.1 |
React | v16.8 |
Browser | Chrome |
a library author may want to offer a fallback media query when no theme is defined.
@fzaninotto In this case, I would encourage the creation of a custom useMediaQuery
. You can use the useTheme
from the core that has a default theme. Would it work for your case?
does useMediaQuery can only be used in function component , how to use it in Class component ..
I confirm that this is the patch I think that we should encourage until we serve the default theme by default. The issue with provided a default theme is that it would require to bundle createMuiTheme()
, this doubles the bundle size of the useMediaQuery
helper, it's not an option.
The unstyled package seems like the perfect opportunity to fix this issue. We could have two versions:
- One with no default theme or callback function, imported from
@material-ui/unstyled
- One with, imported from
@material-ui/core
.
We have done something similar for with Modal. For context, the callback function originates from #16313, to improve the DX.
From the exploration in #26139 did by Sebastian, removing the theme context read can save 0.5kB gzipped in useMediaQuery
when used standalone (if used with another other core components, it won't make a difference). This is an interesting feature for an unstyled package.
Composition gives us all the tools to fix this issue and actually make useMediaQuery
a good candiate for usage outside of Material-UI:
// existing implementation without any knowledge of themes
declare function useMediaQuery(query: string): boolean;
// new implementation
function useThemedMediaQuery(queryInput: string | ((theme: Theme) => string)) {
// default theme
const theme = useTheme();
const query = typeof queryInput === 'function' ? queryInput(theme) : queryInput;
return useMediaQuery(query);
};
useThemedMediaQuery
is just a working title. options
were ignored for simplicity.
@eps1lon The initial implementation was using composition as your codesnippet. It was changed with #16313. 👍 For having the two.
One with no default theme or callback function, imported from @material-ui/unstyled
It seems to me that the System could be a better place for this as it's a utility to help styling components. CC @mnajdova
It seems to me that the System could be a better place for this as it's a utility to help styling components. CC @mnajdova
@michaldudak I would argue that we should probably have implementation in both packages. Why? The useMediaQuery
is useful with any theming solution that you may use, as a util I don't see why it shouldn't be in base. If you use system however, you will likely want to have it there considering the theme values from the system's theme.
In the end, I would lean on MUI Base because it doesn't need a dependency on a style engine. I think that in base, developers will be more likely to import and use it as a standalone helper.