You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js的styled-components主题中使用window.matchMedia实现响应式更新?

问题原因

你定义的theme是静态常量,isCompact属性仅在模块导入时计算一次,后续窗口尺寸变化不会更新该值,ThemeProvider也不会触发下游组件重渲染,因此样式无法同步更新。

解决步骤
  1. 将isCompact改为响应式状态,在_app.js中监听媒体查询变化同步更新状态,再将动态状态注入ThemeProvider即可。修改后的_app.js代码如下:
import { ThemeProvider } from 'styled-components';
import { useState, useEffect } from 'react';

// 断点常量可以抽成单独的配置文件统一管理
const smartPhonePortrait = 320;

const App = ({ Component, pageProps, router }) => {
  // 服务端渲染阶段默认赋值false,避免 hydration 不匹配
  const [isCompact, setIsCompact] = useState(false);

  useEffect(() => {
    const mediaQuery = window.matchMedia(`(min-width:${smartPhonePortrait}px)`);
    // 初始化赋值当前媒体查询匹配结果
    setIsCompact(mediaQuery.matches);

    // 定义媒体查询变化的回调函数
    const handleMediaChange = (e) => {
      setIsCompact(e.matches);
    };

    // 绑定监听事件
    mediaQuery.addEventListener('change', handleMediaChange);

    // 组件卸载时移除监听,避免内存泄漏
    return () => {
      mediaQuery.removeEventListener('change', handleMediaChange);
    };
  }, []);

  const theme = {
    isCompact
  };

  return (
    <ThemeProvider theme={theme}>
      <Component {...pageProps} />
    </ThemeProvider>
  );
};

export default App;
  1. 原来的静态theme.js文件可以删除,断点常量如果需要多处使用,可以单独抽成constants/breakpoints.js导出复用即可。
额外注意

你当前使用的是min-width:320px作为判断条件,即视口宽度≥320px时isCompact为true。如果你期望的是「窄屏移动端(宽度小于320px)使用100%宽度」,需要将媒体查询修改为max-width:${smartPhonePortrait}px。

内容的提问来源于stack exchange,提问作者CodingLittle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 06:36:03