Home > Mobile >  Is there a better way to change style based on screen size on react app?
Is there a better way to change style based on screen size on react app?

Time:06-14

Im using Material UI on my react app and I'm using useMediaQuery and useTheme from mui. This is the code I have right now. Is there a better way to optimize less code? There are only a few style changes between the 2 codes.

const MainPage = () => {
    const theme = useTheme();
    const isMatch = useMediaQuery(theme.breakpoints.down('md'))
    return (
        <div className='mainPage'>
            {
                isMatch ? (
                    <>
                        <Box sx={{ display: "flex", justifyContent: "center", alignContent: "center", flexDirection: "column", padding: "60px 10px 10px 10px" }}>
                            <Box component="img" src={LandingImage} sx={{ width: "100%" }} />
                            <Box sx={{ paddingTop: 8 }}>
                                <Typography sx={{ fontSize: 26, fontWeight: "bold", fontFamily: "sans-serif", textAlign: "center", paddingBottom: 5 }}>About us</Typography>
                            </Box>
                        </Box>
                    </>
                ) : (
                    <>
                        <Box sx={{ display: "flex", justifyContent: "center", alignContent: "center", flexDirection: "row", paddingTop: 20 }}>
                            <Box component="img" src={LandingImage} />
                            <Box sx={{ width: 700, paddingTop: 8 }}>
                                <Typography sx={{ fontSize: 30, fontWeight: "bold", fontFamily: "sans-serif", textAlign: "center", paddingBottom: 5 }}>About us</Typography>
                            </Box>
                        </Box>
                    </>
                )}
        </div>
    )
}

CodePudding user response:

There are several options. The first is to create a style object in javascript, which can be interacted with like normal javascript. You are already doing this in-line, but if we do it in the code above, we can make it dynamic.

const myOuterBoxStyle = {
  display: "flex", 
  justifyContent: "center", 
  alignContent: "center",
  flexDirection: "row",
  paddingTop: 20
}
if (isMatch) {
  myOuterBoxStyle.flexDirection = "column";
  myOuterBoxStyle.paddingTop = undefined;
  myOuterBoxStyle.padding = "60px 10px 10px 10px";
}

Once you do all of the dynamic styling you need, you can make a single return for your component and simply put

<Box sx={{myOuterBoxStyle}}>

The other option is to make a seperate CSS sheet and import it, and then use classes. Something like

.outer-box {
display: "flex";
justify-content: "center";
align-content: "center";
}

.is-match {
flex-direction: "column";
padding: "60px 10px 10px 10px"
}

And then you can either add the is-match class or, perhaps, the is-not-match class depending.

The final option is to use a third-party package that does most of this for you, like Tailwind

CodePudding user response:

As the structure of JSX for mobile / desktop is the same, you could drop one of those two JSX templates, build a variable to store component configuration based on isMatch and pass this variable into component template.


const MainPage = () => {
    const theme = useTheme();
    const isMatch = useMediaQuery(theme.breakpoints.down('md'))

    // Subset of props, to illustrate the idea.
    const config = isMatch ? {fontSize: 26} : {fontSize: 30};

    // Here only root <Box/> is configured, but you can configure all the nested components the same way.
    return (
        <div className='mainPage'>
          <Box sx={config}>[...]</Box>
        </div>
    )
}

(Same with components nested inside <Box/> - the idea is the same - declare some variables with value based on your state and pass them to JSX declaration)

CodePudding user response:

Mui has breakpoints shorthand syntax, as you can check here.

So, for example, your code will also work with:

const MainPage = () => {
  return (
    <div className="mainPage">
      <Box
        sx={{
          display: "flex",
          justifyContent: "center",
          alignContent: "center",
          flexDirection: ["column", "column", "row"],
          paddingTop: ["60px 10px 10px 10px", "60px 10px 10px 10px", 20]
        }}
      >
        <Box component="img" />
        <Box sx={{ width: ["unset", "unset", 700], paddingTop: 8 }}>
          <Typography
            sx={{
              fontSize: [26, 26, 30],
              fontWeight: "bold",
              fontFamily: "sans-serif",
              textAlign: "center",
              paddingBottom: 5
            }}
          >
            About us
          </Typography>
        </Box>
      </Box>
    </div>
  );
};    

In the example above i use the Breakpoints as an array and mui docs says:

The second option is to define your breakpoints as an array, from the smallest to the largest breakpoint.

So imagine that array positions would be: [xs, sm, md, lg, xl] and the breakpoints are equivalent to theme.breakpoints.up.

Another way to do it is use Breakpoints as an object:

Simple example

<Box
   sx={{
      width: {
         xs: 100, // theme.breakpoints.up('xs')
         sm: 200, // theme.breakpoints.up('sm')
         md: 300, // theme.breakpoints.up('md')
         lg: 400, // theme.breakpoints.up('lg')
         xl: 500, // theme.breakpoints.up('xl')
      },
   }}
>
  • Related