useResponsive钩子水合错误- Nextjs Material UI

eivnm1vs  于 2022-08-04  发布在  其他
关注(0)|答案(1)|浏览(95)

我有一个useResponsive钩子,它依赖于mui库中的useMediaQuery。我正在使用Nextjs与应用程序路由器。钩子的初始值返回false,然后返回true,因此存在水合不匹配。我该如何解决此问题?
下面是我的代码:
useResponsive.ts

import { useMediaQuery, useTheme } from '@mui/material';
import {useEffect, useLayoutEffect} from 'react';

export interface IBreakpointsType {
  isMobile: boolean;
  isTablet: boolean;
  isSmallLaptop: boolean;
  isLargeLaptop: boolean;
  isDesktop: boolean;
  isComputer: boolean;
  isLaptop: boolean;
}

const useIsomorphicLayoutEffect =
    typeof window !== 'undefined' ? useLayoutEffect : useEffect

const useResponsive = () => {
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
  const isTablet = useMediaQuery(theme.breakpoints.between('md', 'lg'));
  const isSmallLaptop = useMediaQuery(theme.breakpoints.between('lg', 'xl'));
  const isLargeLaptop = useMediaQuery(theme.breakpoints.between('xl', 'xxl'));
  const isDesktop = useMediaQuery(theme.breakpoints.up('xxl'));
  const isComputer = useMediaQuery(theme.breakpoints.up('lg'));
  const isLaptop = useMediaQuery(theme.breakpoints.between('md', 'xl'));

  useIsomorphicLayoutEffect(() => {
    const handleResize = () => {
      window.dispatchEvent(new Event('resize'));
    };

    window.addEventListener('themeChange', handleResize);

    return () => {
      window.removeEventListener('themeChange', handleResize);
    };
  }, []);

  return {
    isMobile,
    isTablet,
    isSmallLaptop,
    isLargeLaptop,
    isDesktop,
    isComputer,
    isLaptop,
  };
};

export default useResponsive;

字符集
钩子在这里使用:
Footer.tsx

'use client';
import {
  AppBar,
  Box,
  Divider,
  Grid,
  Link,
  Stack,
  Toolbar,
  Typography,
} from '@mui/material';
import React from 'react';

import useResponsive from '../../hooks/useResponsive';

import Flex from '../Flex';

import StyledFooterLogo from './FooterLogo';

const Footer = () => {
  const { isComputer } = useResponsive();
  console.log('isComputer', isComputer)
  return (
    <AppBar
      component="footer"
      sx={{ top: 'auto', bottom: 0, backgroundColor: '#EEEEEE' }}
    >
      <Toolbar variant="dense">
        <Grid
          container
          spacing={{ xs: 1, sm: 2, md: 4 }}
          sx={{ alignItems: 'center', width: '100%' }}
        >
          <Grid item xs={12} sm={6}>
            <Box
              display={isComputer ? 'flex' : 'block'}
              alignItems="center"
              sx={{
                justifyContent: isComputer ? 'left' : 'center',
                '& hr': {
                  mx: 1,
                },
              }}
            >
              <Stack
                direction={isComputer ? 'row' : 'column'}
                sx={{ alignItems: 'center', width: '100%' }}
              >
                <StyledFooterLogo />
                {isComputer && <Divider orientation="vertical" flexItem />}
                <Typography
                  variant="body1"
                  component={Flex}
                  sx={{ justifyContent: 'center' }}
                  className="footerRights"
                >
                  &copy; &nbsp;
                  {new Date().getFullYear()}.All rights reserved.
                </Typography>
              </Stack>
            </Box>
          </Grid>
          <Grid item xs={12} sm={6}>
            <Stack
              direction={isComputer ? 'row' : 'column'}
              spacing={2}
              sx={{
                justifyContent: isComputer ? 'flex-end' : 'center',
                alignItems: 'center',
              }}
            >
              <Link
                href="/privacy-policy/"
                style={{ textDecoration: 'none' }}
                target="_blank"
              >
                <Typography variant="body1" className="footerRights">
                  Privacy Policy
                </Typography>
              </Link>
              <Link
                href="/about/"
                style={{ textDecoration: 'none' }}
                target="_blank"
              >
                <Typography variant="body1" className="footerRights">
                  About
                </Typography>
              </Link>
              <Link
                href="/contact/"
                style={{ textDecoration: 'none' }}
                target="_blank"
              >
                <Typography variant="body1" className="footerRights">
                  Contact
                </Typography>
              </Link>
            </Stack>
          </Grid>
        </Grid>
      </Toolbar>
    </AppBar>
  );
};

export default Footer;


请咨询。


的数据

ve7v8dk2

ve7v8dk21#

也许你可以把你的组件 Package 在一个客户端组件中。
下面是ClientOnly组件

'use client'

import * as React from 'react'

export default function ClientOnly({ children }: { children: React.ReactNode }) {
  const [isMounted, setIsMounted] = React.useState(false)

  React.useEffect(() => {
    setIsMounted(true)
  }, [])

  if (!isMounted) return null

  return children
}

字符集

相关问题