fix: 무한 루프 방지를 위한 스냅샷 업데이트 로직 추가

This commit is contained in:
monoid 2025-10-09 17:37:12 +09:00
parent 6f02f21c7c
commit 283b36bc85
2 changed files with 21 additions and 52 deletions

View file

@ -65,43 +65,13 @@ function useNavItemsData() {
bottomNav: (useCustomItems: boolean) => useCustomItems ? [] : [
createNavItem("tags", "Tags"),
createNavItem("difference", "Diff"),
{ ...accountItem, name: isLoggedIn ? "Profile" : "Login" },
accountItem,
createNavItem("settings", "Settings")
]
})
}, [isLoggedIn]);
}
export function NavList() {
const customNavItems = useNavItems();
const { main, footer } = useNavItemsData();
return (
<aside className="h-dvh flex flex-col">
<nav className="flex flex-col items-center gap-4 px-2 sm:py-5 flex-1">
{customNavItems && (
<>
{customNavItems()}
<Separator />
</>
)}
{main.map(({ key, icon, to, name, className }) => (
<SidebarNavItem key={key} name={name} to={to} className={className}>
{icon}
</SidebarNavItem>
))}
</nav>
<nav className="mt-auto flex flex-col items-center gap-4 px-2 sm:py-5 flex-grow-0">
{footer.map(({ key, icon, to, name, className }) => (
<SidebarNavItem key={key} name={name} to={to} className={className}>
{icon}
</SidebarNavItem>
))}
</nav>
</aside>
);
}
// 사이드바 토글 버튼
export function SidebarToggle({
className,
@ -127,20 +97,6 @@ export function SidebarToggle({
);
}
// 모바일용 사이드바 토글 버튼
export function MobileSidebarToggle() {
const [sidebarState, setSidebarState] = useAtom(sidebarAtom);
const isOpen = sidebarState.isCollapsed;
const onToggle = () => setSidebarState((s) => ({ ...s, isCollapsed: !s.isCollapsed }));
return (
<Button variant="ghost" size="sm" onClick={onToggle} className="size-8 p-0">
{isOpen ? <XIcon className={NAV_ICON_CLASS} /> : <MenuIcon className={NAV_ICON_CLASS} />}
<span className="sr-only">{isOpen ? "Close menu" : "Open menu"}</span>
</Button>
);
}
// 사이드바 네비게이션 아이템
interface SidebarNavItemProps {
children: React.ReactNode;

View file

@ -135,16 +135,29 @@ export const doResetPassword = async (username: string, oldpassword: string, new
}
};
let imutableSnapshot: ReturnType<typeof getUserSessions> = getUserSessions();
const getSnapshot = () => {
const snap = getUserSessions();
// to avoid infinite loop, do not update the snapshot if it hasn't changed
if (JSON.stringify(snap) === JSON.stringify(imutableSnapshot)) {
return imutableSnapshot;
}
return snap;
}
const subscribe = (onChange: () => void) => {
console.log("Auth hook subscribed");
const listener = () => {
console.log("Auth state changed, updating hook");
imutableSnapshot = getSnapshot();
onChange();
};
window.addEventListener("auth", listener);
return () => window.removeEventListener("auth", listener);
}
export function useLogin() {
const hook = useSyncExternalStore(
(onChange) => {
const listener = () => {
onChange();
};
window.addEventListener("auth", listener);
return () => window.removeEventListener("auth", listener);
},
subscribe,
getUserSessions,
);
return hook;