Antd 使用Layout布局刷新会导致左侧栏闪动,怎么解决

Antd 使用Layout布局刷新会导致左侧栏闪动,怎么解决
这是正常时的画面

img


这是闪动时的画面

img


这是代码

<Layout style={{ minHeight: '100vh' }} className={style.container}>
      <Sider style={{ background: '#545c65' }} collapsible collapsed={collapsed} trigger={null}>
        <p className='bigTitle'>{collapsed ? '后台' : '通用后台管理系统'}</p>
        <Menu
          theme="dark"
          defaultSelectedKeys={[location.pathname.slice(1)]}
          mode="inline"
          items={items}
          style={{ background: '#545c65' }}
          onClick={(item) => clickMenu(item)}
        />
      </Sider>
    </Layout>

只要定义了Menu标签的items这个属性,就会出现这样的问题

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
这个问题可能是由于在组件的重新渲染过程中,导致Sider组件重新挂载,从而导致左侧栏闪动。可以尝试以下两种方式解决:

  1. 使用React.memo或PureComponent避免组件的不必要重渲染:
import React, { memo } from 'react';

const MySider = memo(({ items, handleClick }) => {
  return (
    <Layout style={{ minHeight: '100vh' }} className={style.container}>
      <Sider style={{ background: '#545c65' }} collapsible collapsed={collapsed} trigger={null}>
        <p className='bigTitle'>{collapsed ? '后台' : '通用后台管理系统'}</p>
        <Menu
          theme="dark"
          defaultSelectedKeys={[location.pathname.slice(1)]}
          mode="inline"
          items={items}
          style={{ background: '#545c65' }}
          onClick={(item) => handleClick(item)}
        />
      </Sider>
    </Layout>
  )
})

export default MySider;

在使用这个组件的父组件中,可以把items和handleClick封装为函数,在渲染的时候传递给MySider组件:

import React, { useCallback } from 'react';

function MyPage() {
  const items = [...];
  const handleClick = useCallback((item) => {...}, []);

  return (
    <div>
      <MySider items={items} handleClick={handleClick} />
      <div>...</div>
    </div>
  )
}

这样可以确保在父组件的状态或者函数不发生变化的情况下,MySider组件不会重新渲染。

  1. 在Menu组件中传递一个key值来确保Menu组件的重新渲染:
import React from 'react';

function MySider({ items, handleClick }) {
  return (
    <Layout style={{ minHeight: '100vh' }} className={style.container}>
      <Sider style={{ background: '#545c65' }} collapsible collapsed={collapsed} trigger={null}>
        <p className='bigTitle'>{collapsed ? '后台' : '通用后台管理系统'}</p>
        <Menu
          key={items.length} // 添加一个keytheme="dark"
          defaultSelectedKeys={[location.pathname.slice(1)]}
          mode="inline"
          items={items}
          style={{ background: '#545c65' }}
          onClick={(item) => handleClick(item)}
        />
      </Sider>
    </Layout>
  )
}

export default MySider;

这样,每当items数组发生变化时,就会重新渲染整个MySider组件,但其他组件不会受到影响。
如果我的回答解决了您的问题,请采纳!

该回答引用ChatGPT
根据代码,问题出现在使用Antd的Layout组件和Menu组件时,刷新页面时左侧栏会出现闪动。这可能是因为在刷新时,页面重新渲染导致布局重新计算,从而导致闪动。

解决方法:
1. 使用Antd提供的<code>useLayoutEffect</code>钩子,该钩子比<code>useEffect</code>更早执行,能够在DOM更新前立即执行,通过调整布局达到不闪动的效果。

2. 给Sider组件设置<code>collapsedWidth={0}</code>,通常情况下,收起时Sider会有一定宽度,此距离是默认设置的。通过该属性,强制设置收起时Sider的宽度为0,从而减少Sider收缩后与内容区的宽度差异,使得页面切换过程中不会出现闪动。

代码如下:

import React, { useState, useCallback, useLayoutEffect } from 'react';
import { Layout, Menu } from 'antd';

const { Sider } = Layout;
const { SubMenu } = Menu;

const MyLayout = () => {
const [collapsed, setCollapsed] = useState(false);

// 切换菜单栏是否收缩
const toggle = useCallback(() => {
setCollapsed(!collapsed);
}, [collapsed]);

// 点击菜单项
const handleClickMenu = useCallback(() => {
// do something
}, []);


useLayoutEffect(() => {
// 修改侧边栏宽度,解决刷新页面时的缩进问题
const sider = document.querySelector('.ant-layout-sider') as HTMLElement;
if (sider) {
sider.style.width = collapsed ? '80px' : '200px';
}
}, [collapsed]);

const menu = (
<Menu
theme="dark"
mode="inline"
onClick={handleClickMenu}
>
<SubMenu key="sub1" title="Option 1">
<Menu.Item key="1">Option 1.1</Menu.Item>
<Menu.Item key="2">Option 1.2</Menu.Item>
</SubMenu>
<SubMenu key="sub2" title="Option 2">
<Menu.Item key="3">Option 2.1</Menu.Item>
<Menu.Item key="4">Option 2.2</Menu.Item>
</SubMenu>
</Menu>
);

return (
<Layout style={{ minHeight: '100vh' }}>
<Sider
style={{ background: '#545c65', collapsedWidth: 0 }}
collapsible
collapsed={collapsed}
onCollapse={toggle}
trigger={null}
>
<div className="logo" />
{menu}
</Sider>
<Layout>
<div>Content</div>
</Layout>
</Layout>
);
};

引用chatGPT作答,这种闪动可能是因为Antd的Layout组件的默认样式不支持内容高度的变化,导致在刷新页面布局时会出现闪烁的问题。解决这个问题的一种方法是使用CSS样式来覆盖默认的Layout组件样式,以适应内容高度的变化。以下是可能的解决方法:

1.在Layout组件上设置style属性为minHeight: "100vh",以确保Layout组件占满整个视口高度,并且在内容高度变化时不会导致整个布局的变化。

2.在Sider组件上设置style属性为height: "100%",以确保Sider组件占满Layout组件的高度,并且在内容高度变化时不会导致整个布局的变化。

3.在Menu组件上设置style属性为height: "100%",以确保Menu组件占满Sider组件的高度,并且在内容高度变化时不会导致整个布局的变化。

使用下面的代码,可以解决问题:

<Layout style={{ minHeight: '100vh' }} className={style.container}>
  <Sider style={{ background: '#545c65', height: '100%' }} collapsible collapsed={collapsed} trigger={null}>
    <p className='bigTitle'>{collapsed ? '后台' : '通用后台管理系统'}</p>
    <Menu
      theme="dark"
      defaultSelectedKeys={[location.pathname.slice(1)]}
      mode="inline"
      items={items}
      style={{ background: '#545c65', height: '100%' }}
      onClick={(item) => clickMenu(item)}
    />
  </Sider>
</Layout>

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 请看👉 :Antd如何用Menu组件渲染二级或三级目录
  • 以下回答来自chatgpt:

    我没有使用过 Antd 的 Layout 布局,无法对该问题进行解答。建议您查阅 Antd 官方文档中的相关内容,或搜索社区中是否有其他开发者遇到过类似问题并提供了解决方案。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^