material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

Support useMediaQuery without theme

Open fzaninotto opened this issue 5 years ago • 9 comments

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

fzaninotto avatar Aug 02 '19 11:08 fzaninotto

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?

oliviertassinari avatar Aug 02 '19 17:08 oliviertassinari

does useMediaQuery can only be used in function component , how to use it in Class component ..

xjoyzaza avatar Aug 05 '19 01:08 xjoyzaza

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.

oliviertassinari avatar Aug 05 '19 09:08 oliviertassinari

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.

oliviertassinari avatar May 05 '21 09:05 oliviertassinari

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.

oliviertassinari avatar May 05 '21 09:05 oliviertassinari

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 avatar May 05 '21 09:05 eps1lon

@eps1lon The initial implementation was using composition as your codesnippet. It was changed with #16313. 👍 For having the two.

oliviertassinari avatar May 05 '21 09:05 oliviertassinari

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

michaldudak avatar Aug 01 '22 08:08 michaldudak

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.

mnajdova avatar Aug 05 '22 12:08 mnajdova

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.

oliviertassinari avatar Jan 29 '23 20:01 oliviertassinari