
๐ ์ฝ๋์คํ๋ฆฌํ ์ router์์ import๋๋ ๋ถ๋ถ์ ์ ์ฒด import๊ฐ ์๋๋ผ ๋ณ์๋ก ๋ฐ๋ก ๋นผ๋ด์ด ํด๋น ๊ฒฝ๋ก๋ก ์ ๊ทผํ ๋๋ง ๋ก๋๋๋๋ก ํ๋ ๊ธฐ๋ฒ
const MainPage = lazy(() => import("../pages/MainPage"))
๐ ๋ ์ด์ง๋ก๋ฉ์ Suspense์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๋ฉ์ํ๋ฅผ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ฒ
const Loading = <LoadingComponent/>
element: <Suspense fallback={Loading}><MainPage/></Suspense>
๐ fallback์ ํตํด์ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋ ๋๋์ Loading์ปดํฌ๋ํธ๋ฅผ ๋ก๋
๐ MainRouter์์ todo์ ์์ ๋ก ์ค๋ช ์ ํ์๋ฉด, url์ ์ ๋ ฅ์์ todo๋ฅผ ์ ๋ ฅํ์๋ listํ๋ฉด์ด ์ถ๋ ฅ๋์ด์ผํ๊ณ ์ดํ์ todo์ ๊ด๋ จ๋ ํ์ด์ง๋ฅผ ๋ง๋ค๊ธฐ ์ํด์ todo/list, todo/input๊ณผ ๊ฐ์ด url ์ค๊ณ๊ฐ ์ด๋ฃจ์ด์ ธ์ผํ๋ค. ์ด๋ ์ฌ์ฉ๋๋๊ฒ์ด children์ธ๋ฐ
path:"/todo",
element: <Suspense fallback={Loading}><TodoIndex/></Suspense>,
children: [
{
path:"list",
element: <Suspense fallback={Loading}><TodoList/></Suspense>
},
{
path:"",
element: <Navigate to='list' replace={true}></Navigate> // ์ฃผ์์ฐฝ์ todo๋ฅผ ์
๋ ฅํ๋ฉด listPage๋ก redirect
}
]
๐ ํด๋น์ฝ๋์์๋ todo์ ํ์ํ์ด์ง์ ๊ฐ๋ ์ผ๋ก Indexํ์ด์ง ์๋์ children์ ์ฌ์ฉํ์ฌ path,element๋ฅผ ์์ฑํด์ฃผ์๊ณ , list๊ฐ์ ๊ฒฝ์ฐ์๋ todo๋ฅผ ์ ๋ ฅํ์๋ todoํ๋ฉด์ด ๋์ค์ง์๊ณ todoListํ๋ฉด์ด ์ถ๋ ฅ๋๋๋ก Navigate๋ฅผ ๋ง๋ค์๋ค.
๋ํ Indexpage์์๋ Outletํ๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ด๋ถ์ ๋ด๊ธฐ๋ ๋ด์ฉ๋ค์ด Outlet์๋์ ์์ฑ๋๋๋ก ์ค๊ณํ๋ค.
import {Outlet} from "react-router-dom";
import BasicLayout from "../../layouts/BasicLayout.tsx";
function TodoIndex() { // Outlet์ mainRouter์ children
return (
<BasicLayout>
<div>Todo Index Page</div>
<div>
<Outlet></Outlet>
</div>
</BasicLayout>
);
}
export default TodoIndex;
๐ layout์ ๊ฐ๋ฐ ์ด๊ธฐ๋จ๊ณ์ ๊ฐ๋ตํ๊ฒ ํ์ ์ก์์ค์ผ ๋์ค์ ๋ค ๋ค์ง์ด ์๋ ์ฌํ๊ฐ ๋ฐ๋ฐํ์ง ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋ตํ๊ฒ ๋ฏธ๋ฆฌ ํด๋๋๋ค.
๐ layout ์ปดํฌ๋ํธ๋ฅผ ๋ณ๋๋ก ์์ฑํด์ BasicLayout๊ณผ ๊ฐ์ tsxํ์ผ์ ํ๊ทธ์ ๊ฐ์ด ์ฌ์ฉํ๊ฒ ๋ง๋ ๋ค.

๐ ์ด๋ layoutํ์ผ์์๋ ํ์ ํ์ด์ง๋ค์ด ๋ค์ด๊ฐ ๋ด์ฉ์ธ children์ ๊ณต๊ฐ์ ๋ฏธ๋ฆฌ ์์ฑํด๋ฌ์ผํ๋ค.

๐ ํด๋น ํค์๋๋ค์ ๋๋ค url์์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ๋ค์ด๋ค
๐ ๊ฐ์ฅ ์ค์ํ ํค์๋๋ Router๋ url ์ ๋ณด๊ฐ ์๊ณ , url์์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์์ผํ๋๊ฒ.
import {useState} from "react";
import {useSearchParams} from "react-router-dom";
function TodoListComponent() {
const [query, setQuery] = useSearchParams(); // url์ page,size์ ๊ฐ์ ์ ๋ณด๋ฅผ ์ถ์ถํ ์์๋ค.
const changePage = (pageNum:number) => {
query.set("page",""+pageNum); // ์ฟผ๋ฆฌ์คํธ๋ง์ page๊ฐ์ pageNum์ ๋ฃ์ด
setQuery(query) //์ฟผ๋ฆฌ๋ฅผ ์ ์ฉ์์ผ์ค๋ค.
}
const page: number = Number(query.get("page")) || 1
const size: number = Number(query.get("size")) || 10
console.log(size);
console.log(page);
return (
<div>
<div>Todo List Component</div>
</div>
);
}
export default TodoListComponent;
๐ ์ฌ๊ธฐ์ query๋ ํ์ฌ url์ ๋ํ๋ด๊ณ , ํ์ฌ query์ ์ฟผ๋ฆฌ์คํธ๋ง ๋ด๋ถ์ page๋ถ๋ถ์ pageNum์ผ๋ก ๋ณ๊ฒฝํ์ฌ setQuery(์ ์ฉ)ํ๋๊ฒ์ด๋ค.
๐ http://localhost:5173/todo/list?page=11&size=2 ์ด์ ๊ฐ์ url์์ page,size์ ๊ฐ์ ์ถ์ถํ ์ ์๋ ๋ฐฉ๋ฒ.
import {useParams} from "react-router-dom";
function TodoReadPage() {
const {mno} = useParams()
console.log(mno)
return (
<div>
<div>Todo Read Page</div>
</div>
);
}
export default TodoReadPage;
๐ http://localhost:5173/todo/read/321 ์ด์ ๊ฐ์ url์์ read์ ๊ฐ์ ์ถ์ถํ ์ ์๋ ๋ฐฉ๋ฒ.
๐ ๊ทธ๋ ๋ค๋ฉด ๋๊ฐ์ง์ ์ฐจ์ด์ ์ด ๋ญ๊น?
๐ ํ์ด์ง ๋ฒํผ์ ์์ฑํ์ฌ ํ์ด์ง ์ด๋์ด ๋๋๊ฒ์ ๋ง์ ๋ฐฉ๋ฒ๋ค์ด ์กด์ฌํ์ง๋ง, ๋์ผํ ๋ฒํผ์ ๋๋ ์๋ ๋ํ ๋ฆฌ๋ก๋ฉ์ด๋๊ณ ์ํ๊ฐ ๋ณ๊ฒฝ๋์ด์ผ ํ๋๋ฐ, router์์๋ url query๊ฐ ๋ณ๊ฒฝ๋์ด์ผ ์๋์ด ๋๋ useEffect๋ฅผ ์ฌ์ฉํ๋ค. ํ์ง๋ง ๊ทธ๋ ๊ฒ ๋๋ฉด ์ด๋ ํ ๊ฐ ์์ฒด๊ฐ ๋์ผํ ํ์ด์ง ๋ฒํผ์ ๋๋ ์๋๋ง๋ค ๋ณ๊ฒฝ์ด ๋์ด์ผํ๋ค.
refresh ํ ๊ธ
๐ ์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ์ refresh ํ ๊ธ์ด๋ค. on/off์ ๊ฐ์ ๊ฐ๋
์ผ๋ก ํ์ด์ง๋ฒํผ์ ๋๋ ์๋ ํ ๊ธ์ด ์คํ๋์ด ๋ณ๊ฒฝ๋๋ ๊ฐ์ ์ต์ง๋ก ๋ง๋๋๋ฐฉ๋ฒ
time
๐ ๋๋ฒ์งธ ๋ฐฉ๋ฒ์ ํ์ฌ ์๊ฐ์ url์ ์ง์ด๋ฃ์ด ๊ณ์ ๋ณ๊ฒฝ๋๋ url๊ฐ์ ๋ง๋๋๊ฒ์ด๋ค.
useLocation
๐ ๊ฐ์ฅ ๊น๋ํ ๋ฐฉ๋ฒ์ผ๋ก useLocation ๋ด๋ถ์ key์์ฑ์ ์ด์ฉํ๋๋ฐ, key์์ฑ์ url์ ๋ฆฌ๋ก๋ ํ ๋๋ง๋ค ์์ฑ๋๋ key๊ฐ์ ์ด์ฉํ๋ค.
const location = useLocation();
useEffect(() => {
setLoading(true)
getTodoList(page,size).then(data => {
setPageResponse(data)
setLoading(false)
})
},[query, location.key])
return (
<div>
{loading&& <LoadingComponent/>}
<div>Todo List Component</div>
<PageComponent pageResponse={pageResponse}></PageComponent>
</div>
);
}
export default TodoListComponent;
๐ ํด๋น ์ปดํฌ๋ํธ๋ TodoListComponent๋ก useLocation์ ์ด์ฉํ์ฌ url์ ํธ์ถํ ๋๋ง๋ค location์ ์์ฑํด์ฃผ๊ณ , useEffect์ ๊ฐ์ฒด์๋ query์ location.key๋ฅผ ๋ฃ์ด์ค๋ค.
๐ useNavigate๋ Link์ ๋น์ทํ๋ฐ, Link๋ ์ ์ ์ผ๋ก ์์ฑํด๋์ url์ผ๋ก ์ด๋ํ๋ ํ๊ทธ์ด๊ณ , useNavigate๋ ๋์ ์ผ๋ก ๋ณ๊ฒฝ๋์ด ์์ฑ๋ url๋ก ์ด๋ํ๋ ํ๊ทธ์ด๋ค.
const navigate = useNavigate();
const queryStr = createSearchParams({page:page, size:size});
// page์ size์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ฅผ ํฌํจํ๋ ์ฟผ๋ฆฌ์คํธ๋ง ๋ง๋ค๊ธฐ
console.log("queryStr====================="+queryStr);
const moveToRead = (mno:number) => {
navigate({pathname:`/todo/read/${mno}`, search:`?${queryStr}`})
}
// mnoํด๋ฆญ์ ๋์ ์ผ๋ก ์ด๋ํ๋ ๊ฒฝ๋ก๋ฅผ ์์ฑ
๐ ํ์ฌ ์ํฉ์ ์ค๋ช ํ์๋ฉด, list์ ์ถ๋ ฅ๋์ด์๋ todoList๋ฅผ ์ ํํ์๋ readํ์ด์ง๋ก ์ด๋ํ๋๋ฐ, ์ด๋์ ๋์ง๋ง ์ด๋๋ ์ดํ์ url์ ๊ธฐ์กด์ page์ size๊ฐ ๊ธฐ๋ก์ด ์๋๋ ์ํฉ์ด๋ค.
๐ ์ด๋ฌํ ๋ถ์์ฌ๋ฅผ ๋ง๊ธฐ์ํด url์ ์ด์ ์ ๋ด์ฉ์ ์ด์ด๋ถํ์ผํ๋๋ฐ, ๊ทธ๋ ์ฌ์ฉ๋๋ ๊ฐ์ฒด๊ฐ createSearchParams์ด๋ค. ํ์ฌ url ์ฟผ๋ฆฌ์คํธ๋ง์ page์ size๋ฅผ ํฌํจํ๋ url์ ์์ฑํ์ฌ queryStr์ ๋ฃ์ด๋๊ณ , ์ด๋ํ๋ ค๋ moveTodRead ๋ด๋ถ์ navigate๋ฅผ ์ด์ฉํ์ฌ ๊ฒฝ๋ก๋ฅผ ์ค์ ํ๊ณ , search์์์ ๋ฌผ์ํ๋ mno๊ฐ ์์์๋ ์๊ธฐ์ ๋ถ์ธ๊ฒ์ด๊ณ ์์ฑํด๋๋ url์ธ queyStr์ ๋ฃ์ด์ค๋ค.