React에서는 모달을 구현해야 한다면 useState
나 전역 상태를 통해 모달을 구현하였습니다.
const Modal = ({ children }) => (
<div>{children}<div>
)
const Main = () => {
const [open, setOpen] = React.useState(false)
return (
<>
<button onClick={() => setOpen(true)}>모달 열기</button>
{open && <Modal> ... </Modal>}
</>
)
}
그러나 Next.js에서는 별도의 상태없이 모달을 라우팅만으로도 구현할 수 있습니다.
라우팅만으로 모달을 구현하기 위해서는 Next.js가 제공하는 라우팅 방법 중
을 알아야 합니다.
링크는 공식 문서를 번역한 내용이고, 모달을 구현하는 예시도 나와 있으니 참고하시면 좋을 것 같습니다
먼저, 병렬 라우트은 같은 라우트 안에 여러 개의 page.js
를 랜더링하는 방법입니다. 병렬 라우트은 사용하면 세분화된 컴포넌트가 각각 랜더링되기 때문에 각 컴포넌트 별로 로딩/에러 처리에 유리하는 장점이 있습니다. 또한, 모든 컴포넌트가 로드되야 사용자에게 보여지는 것이 아니라 각 컴포넌트가 로드될 때마다 화면에 출력됨으로 빠르게 보여줄 수 있는 부분을 사용자에게 먼저 노출하여 사용자 경험에도 좋은 영향을 줄 수 있는 기능입니다.
병렬 라우팅을 사용하는 방법은 원하는 라우트 폴더에 @folderName
폴더를 만들고 page.js
파일을 생성합니다.
저는 모달을 만들 것이기 때문에 @modal
이라는 이름의 폴더를 만들고 내부에 page.tsx
를 생성해주었습니다.
(저는 타입스크립트를 사용하기 때문에 .tsx
파일을 생성했습니다.)
그리고 현재 라우트 layout.tsx
의 컴포넌트props
에 folderName
가 추가됩니다. 추가된 folderName
프로퍼티는 @folderName
폴더의 page.tsx
가 반환하는 JSX를 값으로 가집니다. 이제 folderName
프로퍼티를 랜더링하고자 하는 위치에 배치시켜주기만 하면 됩니다.
import React from 'react';
const layout = ({ children, modal }: { children: React.ReactNode; modal: React.ReactNode }) => {
return (
<>
{children}
{modal}
</>
);
};
export default layout;
라우트 가로채기는 현재 페이지를 유지하면서 다른 라우트의 레이아웃을 표시할 때 사용할 수 있습니다.
예를 들어 /feed
라우트에서 어떤 사진을 클릭하면 /photo/[id]
로 이동한다고 가정해보겠습니다. 이 때, /feed
에서 랜더링된 항목들이 지워지지 않고 그 위에 /photo/[id]
가 랜더링할 항목들이 보여져야 합니다.
이런 경우에 라우트 가로채기를 사용합니다.
단, 주소창에 직접 경로를 입력하거나, 새로고침을 하면 /feed
에 오버레이 되는 것이 아니라 /photo/[id]
만 랜더링되게 됩니다.
라우트 가로채기를 사용하기 위해서는 (.)folderName
폴더를 만듭니다. 이때 (.)
은 가로채려는 라우트의 위치에 따라 달라집니다.
(.)
는 같은 수준의 라우트를 일치시킬 수 있습니다.(..)
는 한 수준 위의 라우트를 일치시킵니다.(..)(..)
를 사용하여 두 수준 위의 라우트와 일치시킵니다.(...)
를 사용하여 루트 앱 디렉터리에서 라우트를 일치시킬 수 있습니다.위 폴더명 컨벤션을 보면, 자신의 상위 라우트가 형제 라우트는 가로챌 수 있지만, 하위 라우트는 가로챌 수 없다는 것을 알 수 있습니다.
저는 폴더 구조가 꼬여서 중간에 이 부분에서 애먹었습니다.
만들 폴더에 page.tsx
파일을 만들면 완료입니다.
저는 Todo를 수정하는 모달을 만들 것이기 때문에 /edit/[id]
경로를 가로 챘습니다.
(/craete
경로도 가로챘습니다만, 추가로 언급하진 않겠습니다.)
현재 @modal
과 가로채려는 /edit
은 같은 수준의 라우트에 있기 때문에 폴더명은 (.)edit
이 되었습니다.
아래는 각 폴더의 layout.tsx
/ page.tsx
입니다.
/todos/@modal/(.)edit/[id]/page.tsx
import React from 'react';
import { Modal, TodoForm } from '@/components';
const List = [
{
id: '1',
title: 'HTML',
decs: 'HTML5 study',
completed: false,
createAt: new Date(),
},
{
id: '2',
title: 'CSS',
decs: 'CSS3 study',
completed: true,
createAt: new Date(),
},
{
id: '3',
title: 'javaScript',
decs: 'javaScript study',
completed: false,
createAt: new Date(),
},
];
const EditModal = ({
params,
}: {
params: {
id: string;
};
}) => {
const { id, title, decs, completed, createAt } = List.find(({ id }) => id === params.id)!;
return (
<Modal>
<h2 className="text-center font-bold text-4xl">Edit Todo!</h2>
<TodoForm id={id} title={title} decs={decs} completed={completed} createAt={createAt} />
</Modal>
);
};
export default EditModal;
/todos/layout.tsx
import React from 'react';
const layout = ({ children, modal }: { children: React.ReactNode; modal: React.ReactNode }) => {
return (
<>
{children}
{modal}
</>
);
};
export default layout;
그리고 이제 각 TodoItem의 수정 버튼으로 누르면 /todos/edit/[id]
경로로 이동하게 합니다.
const TodoItem = ({ id, completed, title, decs, createAt }: Todo) => {
const router = useRouter();
return (
<li>
...
<button onClick={() => router.push(`/todos/edit/${id}`)}>
<FiEdit />
</button>
...
</li>
);
};
export default TodoItem;
저의 TodoList 페이지입니다.
여기서 수정 버튼을 누르면 아래처럼 경로가 바뀌고 모달이 잘 노출됩니다.
경로 이동으로 모달이 열리도록 구현한 것이기 때문에 브라우저의 뒤로가기/앞으로 가기 기능만으로도 모달을 여닫을 수 있습니다.
정보 감사합니다.