yocontra / react-responsive

CSS media queries in react - for responsive design, and more.
https://contra.io/react-responsive
MIT License
7.04k stars 298 forks source link

React Responsive doesn't work if i refresh the page #269

Closed jack5341 closed 1 year ago

jack5341 commented 3 years ago

React Responsive doesn't work while on mobile

When i working on next.js project from desktop. I open the mobile preview mode and in there have no problem, but if i refresh my page in preview mode react-responsive doesn't work, thats why in production doesn't work

Example Use;

index.js

export default function Home({ logs, version, texts }) {
  const isTablet = useMediaQuery({ query: "(max-width: 1024px)" });

  return (
    <>
      <Box height="8px" background="#107c41"></Box>
      <SimpleGrid columns={isTablet ? 1 : 2}>
        <Infos texts={texts} version={version} logs={logs} />
        <Upload texts={texts} />
      </SimpleGrid>
    </>
  );

upload.js

export default function Upload(props) {
  const value = useContext(ItemStore)
  const { colorMode } = useColorMode();
  const [isUpload, setIsUpload] = useState(false);
  const isTablet = useMediaQuery({ query: "(max-width: 1024px)" });
  const isMobileXL = useMediaQuery({ query: "(max-width: 600px)" });
  const toast = useToast();

  function handleFile(file) {

    if (!file)
      return toast({
        title: "File upload failed",
        status: "warning",
        position: "top-left",
        isClosable: true,
      });

    if (!file.type === excel && !file.type === csv)
      return toast({
        title: "Wrong file type",
        status: "error",
        position: "top-left",
        isClosable: true,
      });

    switch (file.type) {
      case excel:
        readXlsxFile(file).then((rows) => {
          value.setvalue(rows);
        });
        setIsUpload(true);
        break;

      case csv:
        let fileReader = new FileReader();
        fileReader.onloadend = (e) => {
          value.setvalue(
            fileReader.result
              .toString()
              .split("\n")
              .map((e) => e.trim())
              .map((e) => e.split(",").map((e) => e.trim()))
          );
        };
        setIsUpload(true);
        break;

      default:
        toast({
          title: "Wrong file type",
          status: "error",
          position: "top-left",
          isClosable: true,
        });
        break;
    }
  }

  return (
    <Box
      padding={(isTablet ? "0rem" : "4rem") && (isMobileXL ? "1rem" : "4rem")}
      paddingTop={isTablet ? "0rem" : null}
      borderLeft={isMobileXL ? "0" : "1px solid gray"}
    >
      <Text
        color={colorMode === "light" ? "#107c41" : "white"}
        fontSize={(isTablet ? "xl" : "2xl") && (isMobileXL ? "md" : "2xl")}
      >
        <InfoIcon mr="0.5rem" /> {props.texts.uploadlayer}
      </Text>
      <Collapse in={isUpload} animateOpacity>
        <Button
          mt="2"
          _focus="none"
          onClick={() => {
            value.setvalue(null);
            setIsUpload(false);
            document.getElementsByClassName("docs").value = null;
          }}
          size={isMobileXL ? "sm" : "md"}
          leftIcon={<DeleteIcon />}
          colorScheme="green"
          display="block"
          w="100%"
        >
          Delete
        </Button>
      </Collapse>
      <FormControl
        borderRadius="0.5rem"
        border="2px dashed gray"
        mt="3"
      >
        <FormLabel
          color={colorMode === "light" ? "#107c41" : "white"}
          p="1rem"
          fontWeight="bold"
          fontSize={isMobileXL ? "md" : "2xl"}
        >
          {isUpload ? <CheckIcon /> : <DownloadIcon />} Upload your file
        </FormLabel>
        <Input
          className="docs"
          onChange={(e) => handleFile(e.target.files[0])}
          type="file"
          opacity="0"
          accept=".xlsx, .csv"
          border="0px"
        />
      </FormControl>
      {value.value
        ? value.value
            .slice(1)
            .map((element, index) => (
              <Result key={index} label={value.value[0]} items={element} />
            ))
        : null}
    </Box>
  );
}

For better explain;

When i without refresh open preview mode

image

But if I refresh page in preview mode it looks like this;

image

My package.json;

{
  "name": "invoice-printer-next",
  "version": "0.1.1",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "@chakra-ui/core": "^0.8.0",
    "@chakra-ui/icons": "^1.0.6",
    "@chakra-ui/react": "^1.3.4",
    "@emotion/react": "^11.1.5",
    "@emotion/styled": "^11.1.5",
    "framer-motion": "^3.10.2",
    "gray-matter": "^4.0.2",
    "jsonwebtoken": "^8.5.1",
    "next": "10.0.8",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "react-markdown": "^5.0.3",
    "react-youtube": "^7.13.1",
    "read-excel-file": "^5.0.0"
  },
  "devDependencies": {
    "react-responsive": "^8.2.0"
  }
}
kid-icarus commented 3 years ago

Hey @jack5341, I haven't played much with this lib and next.js or any SSR solution for that matter. Could you post a minimum repro in codesandbox?

The overall issue here is that there's no way for the server to know the size of the user-agent viewport which there's nothing this project can really do to solve. However, the worst case scenario should be that the client-side hydration does a full render. While it's not ideal, it at least should not lead to a broken layout like you're describing.

jack5341 commented 3 years ago

Hi @kid-icarus

I was read your documentation about react-responsive, but couldn't find any information about my problem without this section https://github.com/contra/react-responsive#server-side-rendering.

Here is my project before i moved responsibility to css. https://github.com/jack5341/invoice-printer/tree/bff83ebaa1bf8cf4318649320f7841ec761ba631

buudi commented 3 years ago

I have the same issue in next-js any solutions?

amcclure-super commented 3 years ago

I was able to fix the issue by disabling ssr on import:


import dynamic from "next/dynamic"
const MediaQuery = dynamic(() => import("react-responsive"), {
  ssr: false
})
m90khan commented 2 years ago

But how to import useMediaQuery through dynamic const { useMediaQuery } = dynamic(() => import('react-responsive'), { ssr: false, });

m90khan commented 2 years ago

this hook does the job for me import { useState, useEffect } from 'react';

export function useMediaQuery(query) { const [matches, setMatches] = useState(false);

useEffect(() => { const media = window.matchMedia(query); if (media.matches !== matches) { setMatches(media.matches); } const listener = () => { setMatches(media.matches); }; media.addListener(listener); return () => media.removeListener(listener); }, [matches, query]);

return matches; }

ghost commented 2 years ago

How we can use useMediaQuery ??

robbieaverill commented 2 years ago

Is the fix for this as simple as returning null/false when window.matchMedia is unavailable?

yocontra commented 1 year ago

I've added more docs about using this library with next.js to the README - I think that resolves this issue, so going to close this for now.