Poknat The Doggo
Poknat The Doggo

Reputation: 1

Sidebar Flickering/Re-rendering after refresh in browser

This is the UserSidebar

import React, { useState, useEffect } from 'react';
import { Layout, Menu } from 'antd';
import {
  DashboardOutlined,
  AppstoreOutlined,
  HistoryOutlined,
  QrcodeOutlined,
  LogoutOutlined,
  MenuOutlined,
} from '@ant-design/icons';
import { useNavigate, useLocation } from 'react-router-dom';
import { useUserAuthStore } from "../../store/user/useAuth";
import Cookies from 'js-cookie'; // Import js-cookie

const { Sider } = Layout;

const userItems = [
  { label: 'Dashboard', key: '/user/dashboard', icon: <DashboardOutlined style={{ fontSize: '20px' }} /> },
  { label: 'Inventory', key: '/user/inventory', icon: <AppstoreOutlined style={{ fontSize: '20px' }} /> },
  { label: 'History', key: '/user/history', icon: <HistoryOutlined style={{ fontSize: '20px' }} /> },
  { label: 'QR Code', key: '/user/qrcode', icon: <QrcodeOutlined style={{ fontSize: '20px' }} /> },
];

const UserSidebar = () => {
  const [collapsed, setCollapsed] = useState(() => {
    const savedCollapsed = localStorage.getItem('user-sider-collapsed');
    return savedCollapsed ? JSON.parse(savedCollapsed) : false;
  });
  const [current, setCurrent] = useState('/user/dashboard');
  const navigate = useNavigate();
  const location = useLocation();
  const { reset } = useUserAuthStore();

  const onClick = (e) => {
    if (e.key === 'logout') {
      reset();
      sessionStorage.clear();
      localStorage.clear();
      Cookies.remove('authToken'); // Remove the auth token cookie
      navigate('/login', { replace: true });
    } else {
      navigate(e.key, { replace: true }); // Use replace: true to avoid stacking history
      setCurrent(e.key);
    }
  };

  const toggleCollapse = () => setCollapsed(!collapsed);

  useEffect(() => {
    localStorage.setItem('user-sider-collapsed', JSON.stringify(collapsed));
  }, [collapsed]);

  useEffect(() => {
    setCurrent(location.pathname);
  }, [location.pathname]);

  const items = [
    ...userItems,
    {
      key: 'logout',
      label: 'Logout',
      icon: <LogoutOutlined style={{ fontSize: '20px' }} />,
      style: { position: 'absolute', bottom: 50, width: '96%' }
    },
  ];

  return (
    <Sider collapsible collapsed={collapsed} onCollapse={setCollapsed} style={{ backgroundColor: '#0C9B4B', position: 'sticky', zIndex: 1, height: '100vh', overflow: 'hidden' }} trigger={null}>
      <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '16px' }}>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <img style={{ height: '40px', objectFit: 'cover', filter: 'brightness(50%)' }} alt="Logo" src="/SINSSI_LOGO-removebg-preview.png" />
            {!collapsed && <span style={{ color: '#072C1C', fontSize: '32px', fontWeight: '600', marginLeft: '8px', fontFamily: 'Rubik, sans-serif' }}>MIMS</span>}
          </div>
          <div style={{ marginTop: '36px' }}>
            <MenuOutlined style={{ color: '#072C1C', fontSize: '20px', cursor: 'pointer' }} onClick={toggleCollapse} />
          </div>
        </div>
        <Menu theme="light" mode="inline" className="custom-menu" style={{ backgroundColor: '#0C9B4B', marginTop: '22px', color: '#072C1C' }} selectedKeys={[current]} onClick={onClick} items={items} />
      </div>
    </Sider>
  );
};

export default UserSidebar;

import React, { useState, useEffect } from 'react';
import { Layout, Spin } from 'antd'; 
import { Outlet } from 'react-router-dom';
import { HeaderBar, AdminSidebar, UserSidebar } from '../components';
import { useAdminAuthStore } from '../store/admin/useAuth';
import { useUserAuthStore } from '../store/user/useAuth';

const MainLayout = () => {
  const [loading, setLoading] = useState(true); // State to manage loading
  const adminAuth = useAdminAuthStore(); // Admin auth store
  const userAuth = useUserAuthStore(); // User auth store

  // Check if user is admin or regular user (since Auth component handles authentication)
  const isAdmin = adminAuth.token && adminAuth.userData; 
  const isUser = userAuth.token && userAuth.userData; 

  useEffect(() => {
    // Check if token exists to set loading state
    const delay = setTimeout(() => {
      setLoading(false); 
    }, 100); // Short delay for smoother UI experience

    return () => clearTimeout(delay);
  }, [adminAuth.token, userAuth.token]);

  if (loading) {
    return (
      <div className="flex flex-col items-center justify-center h-screen bg-honeydew">
        <img
          className="h-[183px] w-[171px] object-cover mb-4"
          alt="Logo"
          src="/SINSSI_LOGO-removebg-preview.png"
        />
        <Spin size="large" />
        <p className="mt-4 text-darkslategray-200">Loading...</p>
      </div>
    );
  }

  return (
    <Layout style={{ minHeight: '100vh', backgroundColor: '#f0f2f5' }}>
      {/* Render only the appropriate sidebar */}
      {isAdmin && <AdminSidebar />}
      {isUser && !isAdmin && <UserSidebar />}

      <Layout>
        <HeaderBar />
        <Layout.Content style={{ padding: '24px', minHeight: 'calc(100vh - 64px)' }}>
          <Outlet /> {/* Main content rendered here */}
        </Layout.Content>
      </Layout>
    </Layout>
  );
};

export default MainLayout;

I have an issue of flickering or re-rendering in my website when I refresh in my Dashboard, it seems like the AdminSidebar and UserSiderbar role authentication has an issue in re-rendering of the front-end.

I already tried fixing the authentication logic and function, but still the flickering remains, when I tried to use useMemo, it does fix it but just for a moment, after refreshing again the website still flickers but now it is random because of the useMemo.

This is my AdminSidebar as an example:

import React, { useState, useEffect } from 'react';
import { Layout, Menu } from 'antd';
import {
  DashboardOutlined,
  AppstoreOutlined,
  HistoryOutlined,
  QrcodeOutlined,
  UserOutlined,
  LogoutOutlined,
  MenuOutlined,
} from '@ant-design/icons';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAdminAuthStore } from "../../store/admin/useAuth";
import Cookies from 'js-cookie'; // Import js-cookie

const { Sider } = Layout;

const adminItems = [
  { label: 'Dashboard', key: '/admin/dashboard', icon: <DashboardOutlined style={{ fontSize: '20px' }} /> },
  { label: 'Inventory', key: '/admin/inventory', icon: <AppstoreOutlined style={{ fontSize: '20px' }} /> },
  { label: 'History', key: '/admin/history', icon: <HistoryOutlined style={{ fontSize: '20px' }} /> },
  { label: 'QR Code', key: '/admin/qrcode', icon: <QrcodeOutlined style={{ fontSize: '20px' }} /> },
  { label: 'Users', key: '/admin/users', icon: <UserOutlined style={{ fontSize: '20px' }} /> },
];

const AdminSidebar = () => {
  const [collapsed, setCollapsed] = useState(() => {
    const savedCollapsed = localStorage.getItem('admin-sider-collapsed');
    return savedCollapsed ? JSON.parse(savedCollapsed) : false;
  });
  const [current, setCurrent] = useState('/admin/dashboard');
  const navigate = useNavigate();
  const location = useLocation();
  const { reset } = useAdminAuthStore();

  const onClick = (e) => {
    if (e.key === 'logout') {
      reset();
      sessionStorage.clear();
      localStorage.clear();
      Cookies.remove('authToken'); // Remove the auth token cookie
      navigate('/login', { replace: true });
    } else {
      navigate(e.key, { replace: true }); // Use replace: true to avoid stacking history
      setCurrent(e.key);
    }
  };

  const toggleCollapse = () => setCollapsed(!collapsed);

  useEffect(() => {
    localStorage.setItem('admin-sider-collapsed', JSON.stringify(collapsed));
  }, [collapsed]);

  useEffect(() => {
    setCurrent(location.pathname);
  }, [location.pathname]);

  const items = [
    ...adminItems,
    {
      key: 'logout',
      label: 'Logout',
      icon: <LogoutOutlined style={{ fontSize: '20px' }} />,
      style: { position: 'absolute', bottom: 50, width: '96%' }
    },
  ];

  return (
    <Sider collapsible collapsed={collapsed} onCollapse={setCollapsed} style={{ backgroundColor: '#0C9B4B', position: 'sticky', zIndex: 1, height: '100vh', overflow: 'hidden' }} trigger={null}>
      <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '16px' }}>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <img style={{ height: '40px', objectFit: 'cover', filter: 'brightness(50%)' }} alt="Logo" src="/SINSSI_LOGO-removebg-preview.png" />
            {!collapsed && <span style={{ color: '#072C1C', fontSize: '32px', fontWeight: '600', marginLeft: '8px', fontFamily: 'Rubik, sans-serif' }}>MIMS</span>}
          </div>
          <div style={{ marginTop: '36px' }}>
            <MenuOutlined style={{ color: '#072C1C', fontSize: '20px', cursor: 'pointer' }} onClick={toggleCollapse} />
          </div>
        </div>
        <Menu theme="light" mode="inline" className="custom-menu" style={{ backgroundColor: '#0C9B4B', marginTop: '22px', color: '#072C1C' }} selectedKeys={[current]} onClick={onClick} items={items} />
      </div>
    </Sider>
  );
};

export default AdminSidebar;

Upvotes: 0

Views: 55

Answers (0)

Related Questions