8.2 (수)
createPortal
을 사용해서 구현했다.=footer
)을 클릭해서 모달을 띄우고, 데스크탑 버전에서는 왼쪽 위에 위치한 아이콘(=header
)을 클릭해서 모달은 띄운다. (이들은 서로 다른 컴포넌트이다.)header
와 footer
를 Client-Side로 만들 수 밖에 없었다. use client
를 사용해서 Client-Side로 만든다.내가 작성한 코드는 아래와 같다.
// Header
const [showModal, setShowModal] = useState(false);
const [windowSize, setWindowSize] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => {
setWindowSize(window.innerWidth);
};
console.log(windowSize);
handleResize();
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, [windowSize]);
return (
<div className='hidden lg:block lg:pl-5 pt-5 text-white '>
<div className='cursor-pointer' onClick={() => setShowModal(prev => !prev)}>
<BsCardList size={30} />
</div>
<AnimatePresence>
{showModal && (
<Modal
onClose={() => {
setShowModal(false);
}}
windowSize={windowSize}
/>
)}
</AnimatePresence>
</div>
);
// Footer
const [showModal, setShowModal] = useState(false);
const [windowSize, setWindowSize] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => {
setWindowSize(window.innerWidth);
};
console.log(windowSize);
handleResize();
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, [windowSize]);
return (
<div className='sticky bottom-0 flex justify-between items-center z-20 bg-slate-400 text-2xl px-5 py-2 lg:mt-5 lg:hidden'>
<div className='cursor-pointer'>
<ImMap2 size={23} />
</div>
<div>슬라이더</div>
<div className='cursor-pointer' onClick={() => setShowModal(true)}>
<AiOutlineUnorderedList size={25} />
</div>
<AnimatePresence>
{showModal && (
<Modal
onClose={() => {
setShowModal(false);
}}
windowSize={windowSize}
/>
)}
</AnimatePresence>
</div>
);
showModal
과 windowSize
라는 state가 똑같이 선언되어 있고, 브라우저 크기를 측정하는 코드도 똑같다. 이에 따른 모달을 여는 코드도 똑같다..
코드의 낭비라고 생각이 되어, 애니메이션을 위해 client-side를 유지하면서 이를 어떻게 해결할 수 있을까를 고민하는데 시간을 좀 썼다. 이게 괜찮은 방법인지는 아직도 확신이 잘 서지 않지만, 2가지로 구현했다.
page.tsx
내부의 레이아웃에 해당하는 코드를 Section.tsx
라는 파일로 옮기고 Client-Side로 선언한다. 그리고 중복되는 코드는 Section.tsx에 선언한다.(Section.tsx는 Client-Side이기 때문에, useEffect, useState가 사용가능해진다.)<Footer/>
<Header/>
로 선언하는게 아닌, 내부의 HTML 구조를 옮긴 것이다.)1번째 방식으로 해도 애니메이션이 매끄럽게 적용되지는 않았고, Splitter라는 기능을 알게되서 이걸로 다시 구현할 것 같기에 더 이상 코드를 수정하지는 않았다.
<AnimatePresence>
로 코드를 감싸야 한다.정말 배울 것이 너무나도 많다. NextJS도 잘 모르고, TailwindCSS도 잘 몰라서 계속해서 공식 문서를 찾아보면서 하고 있다. 모르는 게 많지만 하나씩 적용해보는게 역시 재밌.짜릿