Call Stack
React
checkForUnmatchedText
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (32797:1)
diffHydratedProperties
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (35055:1)
hydrateInstance
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (36127:1)
prepareToHydrateHostInstance
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (7246:1)
completeWork
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (19769:1)
completeUnitOfWork
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (25963:1)
performUnitOfWork
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (25759:1)
workLoopConcurrent
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (25734:1)
renderRootConcurrent
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (25690:1)
performConcurrentWorkOnRoot
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (24504:1)
workLoop
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\scheduler\cjs\scheduler.development.js (256:1)
flushWork
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\scheduler\cjs\scheduler.development.js (225:1)
MessagePort.performWorkUntilDeadline
node_modules\.pnpm\next@14.2.6_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1\node_modules\next\dist\compiled\scheduler\cjs\scheduler.development.js (534:1) app-index.js:33
Warning: Prop d did not match. Server: "M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4" Client: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"
at path
at svg
at _c (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/lucide-react@0.427.0_react@18.3.1/node_modules/lucide-react/dist/esm/Icon.js:18:11)
at eval (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/lucide-react@0…_react@18.3.1/node_modules/lucide-react/dist/esm/createLucideIcon.js:19:15)
at span
at button
at _c (webpack-internal:///(app-pages-browser)/./src/components/ui/button.tsx:40:11)
at li
at ul
at nav
at Menu (webpack-internal:///(app-pages-browser)/./src/components/sidebar/admin-panel/menu.tsx:34:11)
at div
at aside
at Sidebar (webpack-internal:///(app-pages-browser)/./src/components/sidebar/sidebar.tsx:27:85)
at UseClientHydrationStreamProvider (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/@tanstack+reac…eact-query-next-experimental/build/modern/HydrationStreamProvider.js:22:69)
at ReactQueryStreamedHydration (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/@tanstack+reac…query-next-experimental/build/modern/ReactQueryStreamedHydration.js:20:101)
at QueryClientProvider (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/@tanstack+reac…de_modules/@tanstack/react-query/build/modern/QueryClientProvider.js:27:11)
at Providers (webpack-internal:///(app-pages-browser)/./src/states/providers.tsx:16:11)
at body
at html
at RootLayout (Server)
at RedirectErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…@18.3.1/node_modules/next/dist/client/components/redirect-boundary.js:74:9)
at RedirectBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…18.3.1/node_modules/next/dist/client/components/redirect-boundary.js:82:11)
at NotFoundErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…18.3.1/node_modules/next/dist/client/components/not-found-boundary.js:76:9)
at NotFoundBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…8.3.1/node_modules/next/dist/client/components/not-found-boundary.js:84:11)
at DevRootNotFoundBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…e_modules/next/dist/client/components/dev-root-not-found-boundary.js:33:11)
at ReactDevOverlay (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…/next/dist/client/components/react-dev-overlay/app/ReactDevOverlay.js:87:9)
at HotReload (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…dist/client/components/react-dev-overlay/app/hot-reloader-client.js:321:11)
at Router (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…react@18.3.1/node_modules/next/dist/client/components/app-router.js:207:11)
at ErrorBoundaryHandler (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…ct@18.3.1/node_modules/next/dist/client/components/error-boundary.js:113:9)
at ErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…t@18.3.1/node_modules/next/dist/client/components/error-boundary.js:160:11)
at AppRouter (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…react@18.3.1/node_modules/next/dist/client/components/app-router.js:585:13)
at ServerRoot (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…act@18.3.1__react@18.3.1/node_modules/next/dist/client/app-index.js:112:27)
at Root (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.2.6_@b…act@18.3.1__react@18.3.1/node_modules/next/dist/client/app-index.js:117:11)
app-index.js:33 Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.
3
on-recoverable-error.js:20 Uncaught
Error: Text content does not match server-rendered HTML.
at checkForUnmatchedText (react-dom.development.js:32797:11)
at diffHydratedProperties (react-dom.development.js:35055:9)
at hydrateInstance (react-dom.development.js:36127:3)
at prepareToHydrateHostInstance (react-dom.development.js:7246:3)
at completeWork (react-dom.development.js:19769:13)
at completeUnitOfWork (react-dom.development.js:25963:14)
at performUnitOfWork (react-dom.development.js:25759:5)
at workLoopConcurrent (react-dom.development.js:25734:5)
at renderRootConcurrent (react-dom.development.js:25690:9)
at performConcurrentWorkOnRoot (react-dom.development.js:24504:38)
at workLoop (scheduler.development.js:256:34)
at flushWork (scheduler.development.js:225:14)
at MessagePort.performWorkUntilDeadline (scheduler.development.js:534:21)
react-dom.development.js:16571 Uncaught
Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
at updateHostRoot (react-dom.development.js:16571:57)
at beginWork$1 (react-dom.development.js:18486:14)
at beginWork (react-dom.development.js:26927:14)
at performUnitOfWork (react-dom.development.js:25748:12)
at workLoopSync (react-dom.development.js:25464:5)
at renderRootSync (react-dom.development.js:25419:7)
at recoverFromConcurrentError (react-dom.development.js:24597:20)
at performConcurrentWorkOnRoot (react-dom.development.js:24542:26)
at workLoop (scheduler.development.js:256:34)
at flushWork (scheduler.development.js:225:14)
at MessagePort.performWorkUntilDeadline
와 진짜 이거때문에 미치고 팔짝뛰다가 1080도 공중제비 조질 뻔 했다.
결과적으로 얘기하자면 zustand store에서 불러오는 로그인 상태를
서버에서 인식하는 것과 클라이언트에서 인식하는 것이 달라서 생긴 문제였다.
내가 로그인 상태로 조건부 렌더링을 하도록 걸어놨는데
<Button
onClick={handleUserState}
className="w-full justify-center h-10 mt-5"
variant="ghost"
>
<span className={cn(isOpen ? "mr-4" : "")}>
{isLoggedIn ? <LogOut size={18} /> : <LogIn size={18} />}
</span>
<p className={cn("whitespace-nowrap", isOpen ? "opacity-100" : "opacity-0 hidden")}>
{isLoggedIn ? "Sign out" : "Sign in"}
</p>
</Button>
이런식으로..
근데
const { isLoggedIn, logOut } = authStore((state) => ({
isLoggedIn: state.isLoggedIn,
logOut: state.logout
}))
const handleUserState = () => {
if (isLoggedIn) {
logOut();
} else {
router.push('/login')
}
};
로그인 상태를 불러오는 부분이 useEffect를 사용하지 않고 그냥 불러오는 식으로 구현했을 때 서버와 클라이언트의 인식이 달라 계속 하이드레이션 오류가 났다.
useEffect(() => {
// 클라이언트 사이드에서만 상태를 읽도록 설정
const { isLoggedIn } = authStore.getState();
setIsLoggedIn(isLoggedIn);
}, []);
const handleUserState = () => {
if (isLoggedIn) {
authStore.getState().logout();
} else {
router.push('/login');
}
};
이렇게 csr에서만 상태를 읽도록 설정하니 해결할 수 있었다.
글로는 짧게 적었지만 이거 한다고 한 세시간 박았다 하..
참 부질없는 시간이었을지도..
해결했으니 됐다..
20:46 추가)
이렇게 해두니까 마운트 할 때만 로그인 정보를 업데이트 해서 로그아웃 버튼을 눌러도 버튼이 바뀌지 않는 문제가 생겼다 ㅋㅋㅋ 오류 생길거라고 예상했던 부분이라 바로 고치긴 했는데
아휴.. 진짜 힘드네
const handleClick = () => {
setIsClicked(prevState => !prevState);
}
useEffect(() => {
// 클라이언트 사이드에서만 상태를 읽도록 설정
const { isLoggedIn } = authStore.getState();
setIsLoggedIn(isLoggedIn);
}, [handleClick]);
const handleUserState = () => {
if (isLoggedIn) {
authStore.getState().logout();
handleClick();
console.log(isLoggedIn)
} else {
router.push('/login');
handleClick();
console.log(isLoggedIn)
}
};
대강 이런식으로 버튼 클릭했을 때 실행하는 함수에 handleclick 넣어주고 의존성 배열에 handleclick 넣어서 버튼 클릭할 때 마다 업데이트 하도록 바꿔줬다 일단은 해결
또 오류 생기면 업데이트 하겠다..