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

从CRA迁移至Next.js遇动态CSS类名不匹配警告求助

解决方案:修复Next.js SSR中服务端与客户端样式不匹配问题

问题根源是服务端渲染时没有window对象,导致isMobile初始值在服务端和客户端不一致,触发Hydration不匹配警告。以下是具体修复步骤:

1. 调整isMobile初始状态与客户端初始化逻辑

将isMobile初始值设为undefined(服务端状态),在组件挂载后(客户端环境)再获取真实屏幕宽度并更新状态,确保服务端与客户端首次渲染的内容一致。

修改constructor中的状态初始化:

constructor(props) {
  super(props);

  this.state = {
    title: "",
    forms: {
      search: {
        data: {
          title: "",
          searchLimitTo: (typeof window !== "undefined" &&
            JSON.parse(window.localStorage.getItem("forms")) &&
            JSON.parse(window.localStorage.getItem("forms")).search.data
              .searchLimitTo) || {
            rn: true,
            ing: true
          }
        },
        errors: {}
      }
    },
    isMobile: undefined // 服务端初始化为undefined
  };
  // ... 其余localStorage逻辑不变
}

更新componentDidMount方法,添加初始宽度检测与resize监听:

componentDidMount() {
  // 定义屏幕检测函数
  const checkIsMobile = () => window.innerWidth < 865;
  
  // 初始化客户端isMobile状态
  this.setState({ isMobile: checkIsMobile() });

  // 监听窗口 resize 事件
  window.addEventListener(
    "resize",
    () => {
      this.setState({ isMobile: checkIsMobile() });
    },
    false
  );
}

2. 渲染时处理服务端未初始化状态

在render中,当isMobile为undefined(服务端渲染阶段),默认使用桌面端样式,确保服务端与客户端首次输出的DOM结构一致。

修改render函数:

render() {
  const { isMobile } = this.state;
  // 服务端渲染时默认用桌面端配置,避免Hydration不匹配
  const currentIsMobile = isMobile ?? false;

  return (
    <React.Fragment>
        <div className={styles["outter-first-div"]}>
          <div className={`background`}></div>
          <style jsx>{`
            .background {
              background: ${currentIsMobile
                ? `url(${process.env.NEXT_PUBLIC_IMG_MOBILE}) center / contain no-repeat`
                : `url(${process.env.NEXT_PUBLIC_IMG_DESKTOP}) center / contain no-repeat`};
                height: 100vh;
                width: 100vw;
                position: absolute;
                z-index: -100;
                padding: 0;
                margin: 0;
                top: 0;
                left: 0;
            }
          `}</style>
          <div className={styles.items}>
            <div className="">
              <div className="row">
                <div
                  className={`col-11 col-sm-10 col-md-8 col-lg-7 col-xl-6 text-center ${
                    currentIsMobile ? "mx-auto" : "ms-auto me-5 mx-xl-auto ps-5"
                  } ${styles["initial-search-form-input-div"]}`}
                >
                </div>
              </div>
            </div>
          </div>
        </div>
    </React.Fragment>
  );
}

备选方案:禁用组件SSR(不推荐)

如果上述方案无法解决,可通过next/dynamic将组件设为客户端渲染,但会失去SSR的性能优势:

// 在pages/index.js中导入组件时
import dynamic from 'next/dynamic';

const Index = dynamic(() => import('./Index'), { ssr: false });

export default Index;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 01:25:38