Effitizer 프로젝트의 메인 페이지에는 '지금 구독하기' 버튼이 있다.
원래는 로그인이 되어 있지 않을 때 이 버튼을 누르면 구독 페이지가 아닌 로그인 페이지로 바로 이동했었다.
하지만 아무런 안내 없이 이렇게 리다이렉트 되면 사용자가 불편하다고 느낄 수 있겠다는 생각에 '로그인 페이지로 이동할 것'을 예고하는 toast UI를 추가하기로 했다.
프로젝트가 Next.js + Typescript로 진행되어서 '지금 구독하기' 버튼은 Link 컴포넌트를 사용하고 있었다.
<Link href="/subscribe" passHref>
<a className={styles.subscribeButton}>
지금 구독하기
<ArrowIcon width={48} height={48} color="currentColor" />
</a>
</Link>
Link 컴포넌트는 a 태그와 유사하기 때문에 클릭 시 href의 경로로 이동하는데, toast를 띄워주려면 이 이동을 잠시 막을 필요가 있었다.
그래서 스타일 넣는 용도였던 하위 a 태그에 onClick으로 클릭 이벤트를 막는 코드를 추가하였다.
<Link href="/subscribe" passHref>
<a
onClick={(e) => {
e.preventDefault();
}}
className={styles.subscribeButton}
>
지금 구독하기
<ArrowIcon width={48} height={48} color="currentColor" />
</a>
</Link>
그리고 여기서부터 난관이 시작되었다. (...)
session 객체가 null인지 여부로 로그인 여부를 분기하고, showToast라는 함수를 만들어 안에 react-toastify의 코드를 넣고, 렌더링을 위한 <ToastContainer />
컴포넌트도 추가하였으나 코드가 예상대로 동작하지 않았다.
showToast의 console은 찍혔지만 화면에 뜨는 toast의 UI의 모습이 이상했고, delay 시간을 줬다고 생각했는데 기다림 없이 바로 로그인 페이지로 넘어갔다.
import { useSession } from 'next-auth/react';
import { ToastContainer, toast } from 'react-toastify';
...
const { data: session } = useSession();
...
const showToast = (e: React.MouseEvent) => {
e.preventDefault(); // 링크 이동 막음
console.log('toast 보여주기!');
toast.info(
'구독하시려면 로그인이 필요합니다 😊',
{
autoClose: 2000,
position: toast.POSITION.TOP_RIGHT,
}
);
};
...
<Link href="/subscribe" passHref>
<a
onClick={
session === null
? (e) => showToast(e)
: () => {}
}
className={styles.subscribeButton}
>
지금 구독하기
<ArrowIcon width={48} height={48}
color="currentColor" />
<ToastContainer />
</a>
</Link>
다시 살펴보니 autoClose 시간을 setTimeout의 delay 시간과 혼동했고, react-toastify에 필요한 css CDN이 빠져 있었음을 알게 되어 추가하였다.
처음에는 showToast 함수를 setTimeout 안에 넣었는데, 생각해보니 subscribe 페이지로 이동하는 코드가 2초 뒤에 나타나야 했기 때문에 router.push 코드로 대체했다.
<Link href="/subscribe" passHref>
<a
onClick={
session === null
? (e) => {
showToast(e);
setTimeout(() => {
router.push('/login');
}, 2000);
}
: () => {}
}
className={styles.subscribeButton}
>
지금 구독하기
<ArrowIcon width={48} height={48}
color="currentColor" />
<ToastContainer />
</a>
</Link>
도중에 <ToastContainer />
를 넣는 위치와 toast가 뜨는 시점 조절을 위해 async/await, useEffect 등을 사용해보는 등 여러 시행착오가 많았지만 큰 과정은 위와 같은 과정을 거쳤고, 결국 원하는 동작을 구현하는 데 성공했다.