question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

useMediaQuery - doesn't select the corect state on initial load

See original GitHub issue

🐛 Bug report

When using the hook useMediaQuery(["(min-width: 980px)"]) for example - the state only updates after I manually come near the threashold set, but if I load my component under that width it will not trigger and update the component.

💥 Steps to reproduce

  1. Go to you component with useMediaQuery([]) hook
  2. Load the component under the threadshold set in the hook
  3. Notice that even though the state is correct the component doesn’t re-render
  4. Now - resize your screen
  5. Notice that the component triggers its re-render

🧐 Expected behavior

When using the useMediaQuery hook - when the component is initially loaded - trigger a re-render if under / above the threshold.

🧭 Possible Solution

Checking on load - if

🌍 System information

Software Version(s)
Chakra UI Latest
Browser Chrome Latest
Operating System OXS

📝 Additional information

const CardSection: React.FC = () => {
  const [isLargerThanMd, isDisplayingInBrowser] = useMediaQuery([
    "(min-width: 980px)",
    "(display-mode: browser)",
  ])

  const CardComponents = [
    <Card key={0} title="Cryptocurrencies" link="/dashboard" />,
    <Card key={1} title="Stocks" link="/dashboard" />
  ]

  function determinDevice() {
    let component;
    switch (isLargerThanMd) {
      case false:
        component = <VStack> {CardComponents} </VStack>
        break
      default:
        component = <HStack> {CardComponents} </HStack>
        break
    }
    return component
  }

  return (determinDevice())
}

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:8
  • Comments:13 (2 by maintainers)

github_iconTop GitHub Comments

15reactions
dennemarkcommented, Feb 5, 2021

Current workaround with useEffect seems to fix useMediaQuery, but not the warning. I guess the issue is related to SSR in my case, since I have read about the warning in nextjs and SSR related posts elsewhere (https://github.com/chakra-ui/chakra-ui/discussions/2920 & https://lihautan.com/hydrating-text-content/ )

const MyComponent = () => {
  const [isMinWidthMedium, setIsMinWidthMedium] = useState(false);
  const mediaQuery = useMediaQuery("(min-width: 768px)");

  useEffect(() => {
    if(mediaQuery !== isMinWidthMedium){
      setIsMinWidthMedium(mediaQuery);
    }
  }, [mediaQuery])
  return (
        <Box display="flex" 
        orientation={isMinWidthMedium ? "vertical" : "horizontal" /*has value horiztonal, so if statement is false*/} 
        >
       </Box>
)
}
11reactions
payapulacommented, Mar 19, 2021

I can confirm this happens on SSR (14810). I am using nextjs and the issue is that the server is sending the rendered page for desktop, but the client is not getting re-rendered when this useMediaQuery() hook executed.

This happens only on the initial load. I solved it using this hook as suggested in nextjs repo, modified it a bit to choose useLayoutEffect only on client.

import * as React from "react";

const useIsomorphicLayoutEffect =
  typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;

const useMediaQuery = (width) => {
  const [targetReached, setTargetReached] = React.useState(false);

  const updateTarget = React.useCallback((e) => {
    if (e.matches) {
      setTargetReached(true);
    } else {
      setTargetReached(false);
    }
  }, []);

  useIsomorphicLayoutEffect(() => {
    const media = window.matchMedia(`(max-width: ${width}px)`);
    media.addListener(updateTarget);

    // Check on mount (callback is not called until a change occurs)
    if (media.matches) {
      setTargetReached(true);
    }

    return () => media.removeListener(updateTarget);
  }, []);

  return targetReached;
};

Also, for responsive styles you need to add meta tag --> meta tag for viewport

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

For my case it worked without even adding the above meta tag.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Setting state using React hooks does not work correctly
1 Answer 1 ... This is because the useMediaQuery hook itself has to compute your media query and then give you the result...
Read more >
When to use useCallback, useMemo and useEffect
The useCallback, useMemo, and useEffect are a way to optimize the performance of React-based applications between rerendering of components.
Read more >
Using media queries - CSS: Cascading Style Sheets | MDN
Media queries allow you to apply CSS styles depending on a device's general type (such as print vs. screen) or other characteristics such...
Read more >
Using Breakpoints and Media Queries in Material-UI
Material-UI is one of the most popular React UI component libraries. ... To use the useMediaQuery hook, first import it from Material-UI.
Read more >
CSS Media Min-Width & Max-Width Queries - How They Work
Media queries can be used to target certain resolutions or even specific email ... You can make 50% width fit if you set...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found