Next.js
[Next.js] Next.js 13 - 클라이언트 컴포넌트의 onClick 이벤트 문제 해결하기
수방방
2024. 6. 25. 14:34
🔴 문제 상황
'use client'
import { useState } from 'react'
export default function Navbar() {
const [showMenu, setShowMenu] = useState<boolean>(false)
return (
<button
type="button"
onClick={() => setShowMenu((prev) => !prev)}
className="flex align-middle gap-3 rounded-full border border-gray-20 shadow-sm px-4 py-3 my-auto hover:shadow-lg"
>
<AiOutlineMenu />
<AiOutlineUser />
</button>
)
}
`'use client'`로 선언한 클라이언트 컴포넌트에서 button의 `onClick` 이벤트가 작동하지 않을 뿐더러
Uncaught Error: invariant expected app router to be mounted
at useRouter (navigation.js:131:15)
at HotReload (hot-reloader-client.js:367:46)
at renderWithHooks (react-dom.development.js:11021:18)
at mountIndeterminateComponent (react-dom.development.js:16782:13)
브라우저 개발 도구 콘솔에서 위와 같은 오류가 발생하였습니다.
또한 vscode 에서 새로운 내용을 작성하여 `command + s` 로 저장하면, 웹 페이지에 자동으로 반영되는 것이 아니라 새로고침을 눌러주어야 반영되는 문제점도 발생하였습니다.
🟢 해결책
해결책을 찾는 도중,
https://sentry.io/answers/uncaught-error-invariant-expected-app-router-to-be-mounted/
해당 글을 발견하였습니다.
문제점을 살펴보면, 제대로 작동하지 않던 프로젝트의 `app/layout.tsx` 에는 아래와 같이 `<body>` 태그가 생략되어있었습니다.
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<NextLayout>{children}</NextLayout>
</html>
)
}
Next.js 13 버전은 `app directory` 구조를 사용합니다.
따라서 앱 디렉토리 구조를 사용할 경우 `RootLayout`에 `<html>` 태그 뿐만 아니라 `<body>` 태그가 반드시 포함되어야 합니다.
기존에 `_app.tsx` 와 `_document.tsx` 를 대체해준다고 합니다.
-> 해결 코드
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<NextLayout>{children}</NextLayout>
</body>
</html>
)
}
위의 코드와 같이 `<body>` 태그를 `<html>` 태그 하단에 넣어주었더니 발생하던 문제가 전부 해결되었습니다.