Phase 0: Fix infinite loop in AppSidebar and module settings loading
- Fixed infinite loop by memoizing moduleEnabled with useCallback - Fixed useEffect dependencies to prevent re-render loops - Added loading check to prevent duplicate API calls - Fixed setState calls to only update when values actually change - Removed unused import (isModuleEnabled from modules.config)
This commit is contained in:
@@ -21,7 +21,6 @@ import SidebarWidget from "./SidebarWidget";
|
||||
import { APP_VERSION } from "../config/version";
|
||||
import { useAuthStore } from "../store/authStore";
|
||||
import { useSettingsStore } from "../store/settingsStore";
|
||||
import { isModuleEnabled } from "../config/modules.config";
|
||||
import ApiStatusIndicator from "../components/sidebar/ApiStatusIndicator";
|
||||
|
||||
type NavItem = {
|
||||
@@ -40,7 +39,7 @@ const AppSidebar: React.FC = () => {
|
||||
const { isExpanded, isMobileOpen, isHovered, setIsHovered } = useSidebar();
|
||||
const location = useLocation();
|
||||
const { user } = useAuthStore();
|
||||
const { moduleEnableSettings, isModuleEnabled: checkModuleEnabled } = useSettingsStore();
|
||||
const { moduleEnableSettings, isModuleEnabled: checkModuleEnabled, loadModuleEnableSettings, loading: settingsLoading } = useSettingsStore();
|
||||
|
||||
// Show admin menu only for users in aws-admin account
|
||||
const isAwsAdminAccount = Boolean(
|
||||
@@ -48,11 +47,11 @@ const AppSidebar: React.FC = () => {
|
||||
user?.role === 'developer' // Also show for developers as fallback
|
||||
);
|
||||
|
||||
// Helper to check if module is enabled
|
||||
const moduleEnabled = (moduleName: string): boolean => {
|
||||
// Helper to check if module is enabled - memoized to prevent infinite loops
|
||||
const moduleEnabled = useCallback((moduleName: string): boolean => {
|
||||
if (!moduleEnableSettings) return true; // Default to enabled if not loaded
|
||||
return checkModuleEnabled(moduleName);
|
||||
};
|
||||
}, [moduleEnableSettings, checkModuleEnabled]);
|
||||
|
||||
const [openSubmenu, setOpenSubmenu] = useState<{
|
||||
sectionIndex: number;
|
||||
@@ -68,6 +67,15 @@ const AppSidebar: React.FC = () => {
|
||||
[location.pathname]
|
||||
);
|
||||
|
||||
// Load module enable settings on mount (only once)
|
||||
useEffect(() => {
|
||||
if (!moduleEnableSettings && !settingsLoading) {
|
||||
loadModuleEnableSettings().catch((error) => {
|
||||
console.warn('Failed to load module enable settings:', error);
|
||||
});
|
||||
}
|
||||
}, []); // Empty dependency array - only run on mount
|
||||
|
||||
// Define menu sections with useMemo to prevent recreation on every render
|
||||
// Filter out disabled modules based on module enable settings
|
||||
const menuSections: MenuSection[] = useMemo(() => {
|
||||
@@ -196,7 +204,7 @@ const AppSidebar: React.FC = () => {
|
||||
],
|
||||
},
|
||||
];
|
||||
}, [moduleEnableSettings, moduleEnabled]);
|
||||
}, [moduleEnabled]);
|
||||
|
||||
// Admin section - only shown for users in aws-admin account
|
||||
const adminSection: MenuSection = useMemo(() => ({
|
||||
@@ -282,14 +290,6 @@ const AppSidebar: React.FC = () => {
|
||||
: menuSections;
|
||||
}, [isAwsAdminAccount, menuSections, adminSection]);
|
||||
|
||||
// Load module enable settings on mount
|
||||
useEffect(() => {
|
||||
const { loadModuleEnableSettings } = useSettingsStore.getState();
|
||||
if (!moduleEnableSettings) {
|
||||
loadModuleEnableSettings();
|
||||
}
|
||||
}, [moduleEnableSettings]);
|
||||
|
||||
useEffect(() => {
|
||||
const currentPath = location.pathname;
|
||||
let foundMatch = false;
|
||||
@@ -305,9 +305,15 @@ const AppSidebar: React.FC = () => {
|
||||
});
|
||||
|
||||
if (shouldOpen) {
|
||||
setOpenSubmenu({
|
||||
sectionIndex,
|
||||
itemIndex,
|
||||
setOpenSubmenu((prev) => {
|
||||
// Only update if different to prevent infinite loops
|
||||
if (prev?.sectionIndex === sectionIndex && prev?.itemIndex === itemIndex) {
|
||||
return prev;
|
||||
}
|
||||
return {
|
||||
sectionIndex,
|
||||
itemIndex,
|
||||
};
|
||||
});
|
||||
foundMatch = true;
|
||||
}
|
||||
@@ -330,10 +336,16 @@ const AppSidebar: React.FC = () => {
|
||||
// scrollHeight should work even when height is 0px due to overflow-hidden
|
||||
const scrollHeight = element.scrollHeight;
|
||||
if (scrollHeight > 0) {
|
||||
setSubMenuHeight((prevHeights) => ({
|
||||
...prevHeights,
|
||||
[key]: scrollHeight,
|
||||
}));
|
||||
setSubMenuHeight((prevHeights) => {
|
||||
// Only update if height changed to prevent infinite loops
|
||||
if (prevHeights[key] === scrollHeight) {
|
||||
return prevHeights;
|
||||
}
|
||||
return {
|
||||
...prevHeights,
|
||||
[key]: scrollHeight,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 50);
|
||||
|
||||
Reference in New Issue
Block a user