현재 하나의 라우팅 설정에 children 속성을 이용해서 중첩적인 라우팅 설정을 적용할 수 있지만 페이지가 많아지면 페이지가 너무 복잡해지는 단점이 있다. 그래서 별도의 파일을 만들어 관리하고자 한다.
todoRouter.js
import { Suspense, lazy } from "react";
const Loading = <div>Loading...</div>;
const TodoList = lazy(() => import("../pages/todo/ListPage"));
const todoRouter = () => {
return [
{
path: "list",
element: (
<Suspense fallback={Loading}>
<TodoList />
</Suspense>
),
},
];
};
export default todoRouter;
'/todo/' 경로로 이동할 경우 자동으로 '/todo/list'로 이동하게끔 바꿔주었다.
import { Suspense, lazy } from "react";
import { Navigate } from "react-router-dom";
const Loading = <div>Loading...</div>;
const TodoList = lazy(() => import("../pages/todo/ListPage"));
const todoRouter = () => {
return [
{
path: "list",
element: (
<Suspense fallback={Loading}>
<TodoList />
</Suspense>
),
},
{
path: "",
element: <Navigate replace to="list" />,
},
];
};
export default todoRouter;
ReadPage.js
import { useParams } from "react-router-dom";
const ReadPage = () => {
const { tno } = useParams();
return (
<div className="text-3xl font-extrabold">
Todo Read Page Component {tno}
</div>
);
};
export default ReadPage;
useParams()가 경로 자체의 값을 사용하는데 비해 '?' 이후에 나오는 쿼리스트링은 useSearchParams()를 이용할 수 있다. 예를 들어 목록 페이지에는 페이징/검색 기능으로 인해서 '/todo/list?page=3&size=20'과 유사한 형태의 경로와 쿼리스트링이 사용되는데 이 경우 useSearchParams()를 이용해서 원하는 쿼리스트링의 값을 추출할 수 있다.
ListPage.js
import { useSearchParams } from "react-router-dom";
const ListPage = () => {
const [queryParams] = useSearchParams();
const page = queryParams.get("page") ? parseInt(queryParams.get("page")) : 1;
const size = queryParams.get("size") ? parseInt(queryParams.get("size")) : 10;
return (
<div className="p-4 w-full bg-white">
<div className="text-3xl font-extrabold">
Todo List Page Component {page} --- {size}
</div>
</div>
);
};
export default ListPage;
React-Router를 이용하면 고정된 링크로 이동할 때도 있지만, 대부분은 상황에 따라서 동적으로 데이터를 처리해서 이동하는 경우가 많다. 이럴 때는 Navigator나 Link 대신 useNavigate()를 이용한다.
import { useCallback } from "react";
import BasicLayout from "../../layouts/BasicLayout";
const { Outlet, useNavigate } = require("react-router-dom");
function IndexPage() {
const navigate = useNavigate();
const handleClickList = useCallback(() => {
navigate({ pathname: "list" });
});
const handleClickAdd = useCallback(() => {
navigate({ pathname: "add" });
});
return (
<BasicLayout>
<div className="w-full flex m-2 p-2">
<div
className="text-xl m-1 p-2 w-20 font-extrabold text-center underline"
onClick={handleClickList}
>
LIST
</div>
<div
className="text-xl m-1 p-2 w-20 font-extrabold text-center underline"
onClick={handleClickAdd}
>
ADD
</div>
</div>
<div className="flex flex-wrap w-full">
<Outlet />
</div>
</BasicLayout>
);
}
export default IndexPage;
조회 페이지는 다시 목록으로 이동할 수 있기 때문에 page와 size처럼 쿼리스트링으로 전달되는 데이터들을 유지하면서 이동해야 한다. useSearchParams()를 이용해서 쿼리스트링으로 전달된 데이터를 확인하고 createSearchParams()라는 함수를 이용해서 이동 시에 필요한 쿼리스트링을 만들어내서 navigate()를 이용한 이동 시에 활용한다.
import { useCallback } from "react";
import {
createSearchParams,
useNavigate,
useParams,
useSearchParams,
} from "react-router-dom";
const ReadPage = () => {
const { tno } = useParams();
const navigate = useNavigate();
const [queryParams] = useSearchParams();
const page = queryParams.get("page") ? parseInt(queryParams.get("page")) : 1;
const size = queryParams.get("size") ? parseInt(queryParams.get("size")) : 10;
const queryStr = createSearchParams({ page, size }).toString();
const moveToModify = useCallback(
(tno) => {
navigate({ pathname: `/todo/modify/${tno}`, search: queryStr });
},
[tno, page, size]
);
return (
<div className="text-3xl font-extrabold">
Todo Read Page Component {tno}
<div>
<button onClick={() => moveToModify(tno)}>Test Modify</button>
</div>
</div>
);
};
export default ReadPage;