From e6f2d5f748b625ffc8a9348a612a409c9e2f3fff Mon Sep 17 00:00:00 2001 From: doda Date: Sun, 4 Feb 2024 10:29:24 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9A=B0=ED=84=B0=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jest.setup.js | 2 +- src/components/add/LinkInput.tsx | 2 +- .../common/NavigationBar/NavigationBar.tsx | 4 ++- src/components/common/ToastSection.tsx | 12 +++++---- src/components/home/Thumbnail.tsx | 27 ++++++++++--------- src/hooks/analytics/useRecordPageview.ts | 14 +++++----- src/hooks/common/useInternalRouter.ts | 6 ++++- src/hooks/common/useLoginRedirect.ts | 4 +-- .../common/useRouterQuery/useRouterQuery.ts | 11 +++++--- src/pages/add/tag.tsx | 4 +-- src/pages/password/index.tsx | 17 ++++++------ src/pages/password/sent-email.tsx | 6 +++-- src/pages/signup/email-verified.tsx | 6 ++--- src/pages/signup/index.tsx | 24 +++++++++-------- src/pages/signup/sent-email.tsx | 7 +++-- 15 files changed, 85 insertions(+), 61 deletions(-) diff --git a/jest.setup.js b/jest.setup.js index e3ca084d..3fd6268e 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -3,7 +3,7 @@ import { matchers } from '@emotion/jest'; import '@testing-library/jest-dom'; import '@testing-library/jest-dom/extend-expect'; -jest.mock('next/router', () => require('next-router-mock')); +jest.mock('next/compat/router', () => require('next-router-mock')); window.matchMedia = query => ({ matches: false, diff --git a/src/components/add/LinkInput.tsx b/src/components/add/LinkInput.tsx index 7b4d23dd..f0f1ab17 100644 --- a/src/components/add/LinkInput.tsx +++ b/src/components/add/LinkInput.tsx @@ -64,7 +64,7 @@ export default function LinkInput({ initialLink, openGraph, saveOpenGraph }: Lin return (
- {openGraph ? ( + {openGraph && asPath ? ( { @@ -20,10 +21,11 @@ export default function ToastSection() { const onClickClipboardToast = () => { setClipboardToastVisible(false); - Router.push({ - pathname: currentToast?.clipboardConfig?.type === 'TEXT' ? '/add/text' : '/add/link', - query: { isClipboard: true }, - }); + router && + router.push({ + pathname: currentToast?.clipboardConfig?.type === 'TEXT' ? '/add/text' : '/add/link', + query: { isClipboard: true }, + }); }; const onClickCloseButton = (e: React.MouseEvent) => { diff --git a/src/components/home/Thumbnail.tsx b/src/components/home/Thumbnail.tsx index 48ebe713..02102e03 100644 --- a/src/components/home/Thumbnail.tsx +++ b/src/components/home/Thumbnail.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; import { css, Theme } from '@emotion/react'; import { motion, Variants } from 'framer-motion'; @@ -17,22 +17,23 @@ export interface ContentThumbnailProps } function Thumbnail({ id, type, tags, content, openGraph }: ContentThumbnailProps) { - const { push } = useRouter(); + const router = useRouter(); const moveToInspirationView = (id: number) => { recordEvent({ action: '영감 상세 조회', value: type }); - push( - { - query: { - modal: 'inspirationView', - id, + router && + router.push( + { + query: { + modal: 'inspirationView', + id, + }, }, - }, - { pathname: 'content', query: { id } }, - { - scroll: false, - } - ); + { pathname: 'content', query: { id } }, + { + scroll: false, + } + ); }; return ( diff --git a/src/hooks/analytics/useRecordPageview.ts b/src/hooks/analytics/useRecordPageview.ts index 3c6b7535..a976d149 100644 --- a/src/hooks/analytics/useRecordPageview.ts +++ b/src/hooks/analytics/useRecordPageview.ts @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; import { IS_PRODUCTION } from '~/constants/common'; import { gaPageview } from '~/libs/ga'; @@ -14,9 +14,11 @@ export function useRecordPageview() { mixpanelTrack('Page view', { url, category: process.env.WEB_VERSION }); }; - if (IS_PRODUCTION) router.events.on('routeChangeComplete', recordPageview); - return () => { - if (IS_PRODUCTION) router.events.off('routeChangeComplete', recordPageview); - }; - }, [router.events]); + if (router) { + if (IS_PRODUCTION) router.events.on('routeChangeComplete', recordPageview); + return () => { + if (IS_PRODUCTION) router.events.off('routeChangeComplete', recordPageview); + }; + } + }, [router]); } diff --git a/src/hooks/common/useInternalRouter.ts b/src/hooks/common/useInternalRouter.ts index cd7c9cd5..5c4a24db 100644 --- a/src/hooks/common/useInternalRouter.ts +++ b/src/hooks/common/useInternalRouter.ts @@ -1,4 +1,4 @@ -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; import { UrlObject } from 'url'; export type RouterPathType = @@ -25,6 +25,10 @@ export type RouterPathType = export default function useInternalRouter() { const router = useRouter(); + if (!router) { + throw new Error('useInternalRouter must be used under Next.js Pages Router'); + } + return { ...router, push(path: RouterPathType, as?: UrlObject | string, options?: TransitionOptions) { diff --git a/src/hooks/common/useLoginRedirect.ts b/src/hooks/common/useLoginRedirect.ts index 7f01a98e..b0cff3e6 100644 --- a/src/hooks/common/useLoginRedirect.ts +++ b/src/hooks/common/useLoginRedirect.ts @@ -1,4 +1,4 @@ -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; import { sessionStorageRedirectKey } from '~/constants/sessionStorage'; @@ -15,7 +15,7 @@ export function useLoginRedirect() { const goRedirect = () => { const redirect = getRedirect(); if (!redirect) return; - router.replace(redirect); + router && router.replace(redirect); sessionStorage.removeItem(sessionStorageRedirectKey); }; diff --git a/src/hooks/common/useRouterQuery/useRouterQuery.ts b/src/hooks/common/useRouterQuery/useRouterQuery.ts index 81a7be65..76c8d0cc 100644 --- a/src/hooks/common/useRouterQuery/useRouterQuery.ts +++ b/src/hooks/common/useRouterQuery/useRouterQuery.ts @@ -1,4 +1,4 @@ -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; function useQueryParam(key: string): string | string[] | undefined; @@ -8,8 +8,13 @@ function useQueryParam( key: string, parser?: (value: string | string[]) => T ): (string | string[] | T) | undefined { - const { query } = useRouter(); - const result = query[key]; + const router = useRouter(); + + if (!router) { + throw new Error('useQueryParam must be used under Next.js Pages Router'); + } + + const result = router.query[key]; if (result === undefined) return undefined; if (parser) return parser(result); diff --git a/src/pages/add/tag.tsx b/src/pages/add/tag.tsx index 1e8eb424..da8c6502 100644 --- a/src/pages/add/tag.tsx +++ b/src/pages/add/tag.tsx @@ -1,5 +1,5 @@ import { useCallback, useRef, useState } from 'react'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; import { motion } from 'framer-motion'; import { GhostButton } from '~/components/common/Button'; @@ -72,7 +72,7 @@ export default function TagPage() { { - router.back(); + router && router.back(); }} > 완료 diff --git a/src/pages/password/index.tsx b/src/pages/password/index.tsx index 34fe6d67..0f355a5f 100644 --- a/src/pages/password/index.tsx +++ b/src/pages/password/index.tsx @@ -1,5 +1,5 @@ import { FormEvent, useState } from 'react'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; import { css, Theme } from '@emotion/react'; import { CTAButton } from '~/components/common/Button'; @@ -16,17 +16,18 @@ import { validator } from '~/utils/validator'; export default function PasswordReset() { const { fireToast } = useToast(); const email = useInput({ useDebounce: true }); - const { push } = useRouter(); + const router = useRouter(); const [emailError, setEmailError] = useState(''); const { mutate: sendPasswordResetEmailMutation, isLoading: isSendPasswordResetEmailLoading } = useSendPasswordResetEmailMutation({ onSuccess: () => { - push({ - pathname: '/password/sent-email', - query: { - email: email.value, - }, - }); + router && + router.push({ + pathname: '/password/sent-email', + query: { + email: email.value, + }, + }); }, onError: () => { fireToast({ diff --git a/src/pages/password/sent-email.tsx b/src/pages/password/sent-email.tsx index ecdb08ae..78c0246a 100644 --- a/src/pages/password/sent-email.tsx +++ b/src/pages/password/sent-email.tsx @@ -1,4 +1,4 @@ -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; import { css, Theme } from '@emotion/react'; import { CTAButton } from '~/components/common/Button'; @@ -8,7 +8,9 @@ import { FixedSpinner } from '~/components/common/Spinner'; import useInternalRouter from '~/hooks/common/useInternalRouter'; export default function SentPasswordResetEmail() { - const { query } = useRouter(); + const router = useRouter(); + if (!router) throw new Error('No router'); + const { query } = router; const { push } = useInternalRouter(); return ( diff --git a/src/pages/signup/email-verified.tsx b/src/pages/signup/email-verified.tsx index 66ebf5b6..dcc19a84 100644 --- a/src/pages/signup/email-verified.tsx +++ b/src/pages/signup/email-verified.tsx @@ -1,5 +1,5 @@ import { FormEvent, useState } from 'react'; -import Router from 'next/router'; +import { useRouter } from 'next/compat/router'; import { css, Theme } from '@emotion/react'; import { CTABottomButton } from '~/components/common/Button'; @@ -19,6 +19,7 @@ import { validator } from '~/utils/validator'; export default function SignUpEmailVerified() { const { fireToast } = useToast(); + const router = useRouter(); const queryEmail = useRouterQuery('email', String); const nickname = useInput({ useDebounce: true }); @@ -56,8 +57,7 @@ export default function SignUpEmailVerified() { confirmPassword: passwordRepeat.value, }); - // NOTE: 이렇게 작성하지 않으면 router.push가 되지않는 이슈 - Router.push({ pathname: '/signup/information', query: { email: queryEmail } }); + router && router.push({ pathname: '/signup/information', query: { email: queryEmail } }); }; // NOTE: 닉네임 에러 메세지 설정 이펙트 diff --git a/src/pages/signup/index.tsx b/src/pages/signup/index.tsx index 49e91c4f..6af8270b 100644 --- a/src/pages/signup/index.tsx +++ b/src/pages/signup/index.tsx @@ -1,5 +1,5 @@ import { FormEvent, useEffect, useState } from 'react'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; import { css, Theme } from '@emotion/react'; import { CTAButton } from '~/components/common/Button'; @@ -111,12 +111,13 @@ function useSignupWithCheckingEmail(email: string) { const { mutate: emailSendMutate } = useSignupSendEmailMutation({ onSuccess: () => { recordEvent({ action: 'Signup', value: '이메일 인증 요청', label: '이메일 발송 화면' }); - router.push({ - pathname: '/signup/sent-email', - query: { - email: email, - }, - }); + router && + router.push({ + pathname: '/signup/sent-email', + query: { + email: email, + }, + }); }, onError: data => { if (data.message) fireToast({ content: data.message }); @@ -155,10 +156,11 @@ function useSignupWithCheckingEmail(email: string) { label: '이메일 발송 화면', }); fireToast({ content: '이미 인증된 메일입니다.' }); - router.push({ - pathname: '/signup/email-verified', - query: { email }, - }); + router && + router.push({ + pathname: '/signup/email-verified', + query: { email }, + }); } else { emailSendMutate({ email }); } diff --git a/src/pages/signup/sent-email.tsx b/src/pages/signup/sent-email.tsx index b60b862b..e0ce8de7 100644 --- a/src/pages/signup/sent-email.tsx +++ b/src/pages/signup/sent-email.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/compat/router'; import { css, Theme } from '@emotion/react'; import { CTAButton, FilledButton } from '~/components/common/Button'; @@ -15,7 +15,7 @@ import { recordEvent } from '~/utils/analytics'; import { validator } from '~/utils/validator'; export default function SignupSentEmail() { - const { query, push } = useRouter(); + const router = useRouter(); const { fireToast } = useToast(); const [isModalOpen, setIsModalOpen] = useState(false); const { @@ -31,6 +31,9 @@ export default function SignupSentEmail() { isLoading: emailSendingLoading, } = useSignupSendEmailMutation({}); + if (!router) throw new Error('router is not defined'); + const { query, push } = router; + const handleEmailChecking = () => { if (query.email !== undefined && validator({ type: 'email', value: query.email as string })) { checkEmailStatusMutate({ email: query.email as string });