如何在 next.js 中使用带有样式组件主题的 window.matchMedia?

Posted

技术标签:

【中文标题】如何在 next.js 中使用带有样式组件主题的 window.matchMedia?【英文标题】:how to use window.matchMedia in next.js with style components theme? 【发布时间】:2022-01-08 09:41:37 【问题描述】:

我有一个主题:

const smartPhonePortrait = 320;


const theme = 
  isCompact:
    typeof window !== 'undefined'
      ? window.matchMedia(`(min-width:$smartPhonePortraitpx)`).matches
      : false
;

export default theme;

然后我将此主题添加到我的提供者

_app.js 内部:

import  ThemeProvider  from 'styled-components';
import theme from '../theme';

const App = ( Component, pageProps, router ) => 
  return (
    <ThemeProvider theme=theme>
     ... my app
    </ThemeProvider>
  );
;

在我的样式化组件中,我这样做:

const Item = styled.div`
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: $(props) => (props.theme.isCompact ? '100%' : '48%');
`;

这适用于第一次渲染,但是当我更改屏幕尺寸时它不会更新。 如果我在移动设备中,我会得到flex-basis 100%,但如果我将屏幕尺寸更改为桌面,我不会得到48%

如何让它发挥作用?

【问题讨论】:

(min-width: 320px) 媒体查询仍然适用于桌面屏幕尺寸。您需要创建一个不同的查询来匹配桌面屏幕尺寸。 【参考方案1】:

你可以做一个钩子:

import  useState, useCallback, useEffect  from 'react';
const useMediaQuery = (width) => 
  const [targetReached, setTargetReached] = useState(false);

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

  useEffect(() => 
    if (typeof window !== 'undefined') 
      const media = window.matchMedia(`(max-width:$widthpx)`);
      media.addListener(updateTarget);

      if (media.matches) 
        setTargetReached(true);
      

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

  return targetReached;
;

export default useMediaQuery;

然后在您的 __app.js 中导入它并将其添加到您的主题中:

import MediaQuery from 'hooks/useMedia';

const isCompact = MediaQuery (576);

const useTheme =  ...theme, isCompact ;

<ThemeProvider theme=useTheme>
  ... my app
</ThemeProvider>

【讨论】:

以上是关于如何在 next.js 中使用带有样式组件主题的 window.matchMedia?的主要内容,如果未能解决你的问题,请参考以下文章

带有 Next.js 和样式化组件的本地字体

带有 next.js 的 material-ui 样式

使用 next.js 和样式化组件重新加载时的 Flash Of Unstyled Text (FOUT)

Next.Js 带有样式组件的 React 应用程序。警告:道具 `className` 不匹配。服务器:“x” 客户端:“y”

如何在 react 和 next js 中使用 Styled 组件创建全局样式,使用 css 文件和 styled 组件的组合是不是更好?

如何在 Next.js 的活动页面上设置链接组件的样式