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

Next.js 14集成Fluent UI出现className服务端客户端不匹配问题求助

服务端渲染与客户端渲染className不匹配问题(Fluent UI + Next.js 14)

遇到服务端渲染与客户端渲染的className不匹配问题,查阅相关话题后未找到适配自身场景的解决方案。使用Microsoft Fluent UI组件库,多个组件均出现该错误。

环境版本

  • nextjs: 14.0.4
  • react: 18
  • fluentui/react: 8.113.1

layout.tsx代码

import Navbar from "./components/Navbar"
import NavbarAndUser from "./components/NavbarAndUser";
import UserPanel from "./components/UserPanel"
import TestSideBar from "./components/TestSideBar"
import './globals.css'
import { initializeIcons } from '@fluentui/react/lib/Icons';

initializeIcons();

export const metadata = {
  title: 'Next.js',
  description: 'Generated by Next.js',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
     
      <body>
        <div className="page-container">
          <div className='navbar'>
            <NavbarAndUser /> 
          </div>
          <div className='sidebar'>
            <TestSideBar />
          </div>
        </div>
       
        {children}
        
      </body>
    </html>
  )
}

侧边栏组件代码(TestSideBar.tsx)

"use client";

import React, { useState } from 'react';
import { Nav, INavLinkGroup, IconButton,Stack, IStackStyles, INavStyles,IStyle, IButtonStyles, Text, ITextStyles} from '@fluentui/react';
import { useRouter } from 'next/navigation'
import { initializeIcons } from '@fluentui/react/lib/Icons';

initializeIcons();

const SidebarWithButton: React.FunctionComponent = () => {
  const [isOpen, setIsOpen] = useState(false);
  const router = useRouter()

  function _onRenderGroupHeader(group: INavLinkGroup): JSX.Element {
    return (
      <Text
        variant='xLarge'
        styles={isOpen ? navLinkOpenHeaderStyles : navLinkCloseHeaderStyles}
      >{group.name}</Text>
    );
  }

  const toggleSidebar = () => {
    setIsOpen(!isOpen);
  };

  const onClick = (e:any,item:any) => {
    e.preventDefault();
    router.push(item.url);
  };

  return (
    <Stack styles={isOpen ? openNavStackStyles : closedNavStackStyles}>
      <Stack horizontalAlign='start' styles={{root:{borderBottom:'1px solid #d8d8d8'}}}>
        <Stack.Item>
          <IconButton
            iconProps={{ iconName: 'GlobalNavButton' }} 
            styles={navButtonStyles}
            onClick={toggleSidebar}
          />
        </Stack.Item>
      </Stack>
      <Stack.Item>
        <Nav
          onRenderGroupHeader={_onRenderGroupHeader}
          onLinkClick={onClick}
          groups={navLinkGroups} 
          isOnTop={false}
          styles={navStyles}         
        />
      </Stack.Item>
    </Stack>
  );
};

const navbarIconStyles = {
  color: 'black',
  padding:'0 0.5rem'
};

const navLinkGroups: INavLinkGroup[] = [
  {
    name: 'Redovisning',
    links: [
      {
        name: 'Aviseringlistor',
        url: '/',
        key: 'key1',
        iconProps: {
          iconName: 'WaitlistConfirm',
          style: navbarIconStyles
        },  
      },     
      {
        name: 'Filer',
        url: '/Filer',
        key: 'key2',   
        iconProps: {    
          iconName: 'DocumentManagement',
          style: navbarIconStyles
        },      
      },   
    ],
  },
  {
    name:'Administration',
    links:[
      {
        name: 'Byta lösenord',
        url: '/ChangePassword',
        key: 'key3',
        iconProps: {
          iconName: 'LockSolid',
          style: navbarIconStyles
        },  
      },
      {
        name: 'Logga ut',
        url: '/2',
        key: 'key4',
        iconProps: {
          iconName: 'SignOut',
          style: navbarIconStyles
        }, 
      },   
    ]
  }
];

const closedNavStackStyles: Partial<IStackStyles> = {
  root: {
    position: 'relative',
    height: '100%',
    width: '40px!important',
    overflow: 'hidden',
    overflowX: 'hidden',
    backgroundColor:'#EFEFEF',
    borderRight:'1px solid #D8D8D8',
  },
};

const openNavStackStyles: Partial<IStackStyles> = {
  root: {
    height: '100%',
    width: 200,
    overflow: 'hidden',
    position: 'relative',
    backgroundColor:'#EFEFEF',
    borderRight:'1px solid #D8D8D8',
  },
};

const navLinkOpenHeaderStyles : Partial<ITextStyles> = {
  root:{
    padding:'0rem 1rem',
    fontWeight:'bold',
    color:'black',
    width:'100%',
  }
};

const navLinkCloseHeaderStyles : Partial<ITextStyles> = {
  root:{
    display:'none',
  }
};

const navButtonStyles: Partial<IButtonStyles> = {
  root:{
    width:'100%', 
    color:'black', 
    paddingLeft: '0.6rem', 
  },
  rootHovered:{
    backgroundColor:'white!important',
    boxShadow: '0 4px 8px 0 rgba(0, 0, 0, 0.2)',
    color:'black!important',
  },
};

const navLinkStyles: Partial<IStyle> = {
  link: {
    selectors: {
      '&:hover, &:focus': {
        color: 'black', 
        backgroundColor:'white!important',
        boxShadow: '0 4px 8px 0 rgba(0, 0, 0, 0.2)',
      },
    },
  },
};

const navStyles: Partial<INavStyles> = {
  root:{
    marginTop:'2rem',
  },
  link: {
    navLinkStyles,
  },
  groupContent:{
    marginBottom:'0rem',
  },
};
export default SidebarWithButton;

next.config.js代码

/** @type {import('next').NextConfig} */
const nextConfig = {
    reactStrictMode: false,
    compiler: {
        // Enables the styled-components SWC transform
        styledComponents: {
            displayName: false,
        }
    }
}

module.exports = nextConfig

恳请帮忙解决该问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 03:23:11