멀티페이지 어플리케이션 단점
> 항상 새 콘텐츠를 가져와야 함
> 새로운 HTTP 요청을 전송하고 새로운 응답을 받는 과정에서 사용자의 흐름이 중단될 수도 있음
> 지연이 발생할 수 있음
> 사용자 경험 저하
> 복잡한 사용자 인터페이스 구축 시 싱글 페이지 어플리케이션 사용
SPA
> 최초 HTML 요청 하나만 전송
> HTML 파일과 추가적인 JS 다운로드 되고 클라이언트에서 실행되는 추가 JS 코드는 사용자가 화면에서 보는 것들을 실제로 조절
SPA에서 라우팅사용
> 클라이언트 측에 리액트 코드 추가 가능하고 이것이 사용중이 URL을 감시 URL 이 변경될 떄마다 작동하여 URL 이 변경되면 화면에 다른 콘텐츠를 표시하게 됨
> 백엔드로부터 새 HTML 파일을 로딩하지 않고 약간의 클라이언트 측 코드를 추가하여 간단히 URL을 감시하다가 URL 이 변경되면 다른 리액트 컴포넌트를 로딩
라우터 주소 등록 방법
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import HomePage from "./pages/Home.js";
import ProductsPage from "./pages/Products.js";
import RootLayout from "./pages/Root.js";
import ErrorPage from "./pages/Error.js";
import ProductDetailPage from "./pages/ProductDetail.js";
const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
errorElement: <ErrorPage />,
children: [
{ index: true, element: <HomePage /> },
{ path: "products", element: <ProductsPage /> },
{ path: "products/:productId", element: <ProductDetailPage /> },
],
},
]);
function App() {
// 위에서 생성한 router를 RouterProvider에 넣어준다
return <RouterProvider router={router} />;
}
export default App;
path : 도메인 뒤에 붙는 경로 ex) https://test.com 가 도메인이라고 치고 https://test.com/sample 이라는 주소를 만들고 싶으면 path : "/sample"을 입력 하면 됨
element : 관련한 컴포넌트를 import 해오면 됨
errorElement : 페이지에 오류났을 때 띄울 페이지
children : 자녀 라우트 정의, path에 상대경로를 작성했는데 래퍼 라우트 경로 뒤에 첨부되는 것을 의미
index:true 부모 라우트가 현재 활성이면 표시되어야 하는 기본 라우트를 표시할 때 사용
ex) path:'products' 의 경우 https://test.com/products
동적 path : /:를 붙임
{ path: "products/:productId", element: <ProductDetailPage /> },
ex) path:"products/:productId" 라고 작성을 하면
https://test.com/products/1 URL이 입력되었을 때
ProductDetailPage로 넘어감
래핑 라우트
import { Outlet } from "react-router-dom";
import MainNavigation from "../components/MainNavigation";
function RootLayout() {
return (
<>
<MainNavigation />
<main>
<Outlet />
</main>
</>
);
}
export default RootLayout;
Outlet 위치에는 자녀 컴포넌트를 띄우게 되고
그걸 감싸는 RootLayout은 항상 자녀 컴포넌트의 컴포넌트 요소로 감싼 형태로 나타나게 된다.
이 컴포넌트에서 module.css적용시 자녀 컴포넌트에도 적용가능
다른 Path로 이동 방법
잘못된 방법
<a href="/">HOME</a>
이 웹사이트를 지원하는 서버에 새로운 요청을 하게 됨
그 서버는 SPA를 구성하는 싱글 HTML 을 제공 > 모든 JS 코드를 로딩 > 리액트 애플리케이션을 재시작
사이트 성능에 피해를 줌 > SPA의 장점을 잃게 됨
올바른 방법 > Link 사용
요청을 전송하는 기본 설정을 막고 리액트 라우터가 새 URL 을 알고 새 URL에 맞는 적절한 요소를 로딩하도록 해야함
import { Link, useNavigate } from "react-router-dom";
function HomePage() {
const navigate = useNavigate();
function navigateHandler() {
navigate("/products");
}
return (
<>
<h1>My Home Page</h1>
<p>
Go to
<Link to="products">the list of products</Link>
</p>
<p>
<button onClick={navigateHandler}>Navigate</button>
</p>
</>
);
}
export default HomePage;
Link는 배후에서 앵커 요소를 렌더링, 요소에 대한 클릭을 감시
링크를 클릭했을 때 전송하는 브라우저 기본 설정을 막아줌
라우트 정의를 확인하여 그에 맞춰 페이지를 업데이트.
적절한 콘텐츠를 로딩, URL을 바꾸지만 새로운 HTTP요청은 전송하지 않음
강제 라우팅 : navigate()
NavLink
import { NavLink } from "react-router-dom";
import classes from "./MainNavigation.module.css";
function MainNavigation() {
return (
<header className={classes.header}>
<nav>
<ul className={classes.list}>
<li>
<NavLink
to="/"
className={({ isActive }) =>
isActive ? classes.active : undefined
}
end
>
Home
</NavLink>
</li>
<li>
<NavLink
to="/products"
className={({ isActive }) =>
isActive ? classes.active : undefined
}
>
Products
</NavLink>
</li>
</ul>
</nav>
</header>
);
}
export default MainNavigation;
Link와 달리 className 프로퍼티 추가시에 실제로 문자열을 받는 일반적인 className 프로퍼티가 아닌 함수를 받는 프로퍼티. 그 함수는 앵커 태그에 추가되어야 하는 css 클래스 이름을 리턴 > 그 함수는 자동적으로 객체를 받음 > 여기에 isActive 속성을 할당 할 수 있음
isActive 는 react-router-dom 에서 제공
현재 라우트가 활성인 경우 true 비활성인 경우 false
조건부 css 활용 가능
NavLink뒤에 end를 붙이면 현재 활성인 라우트 URL 뒤에 이 경로로 끝나고 그 뒤에 아무런 path 가 없을 시에만 이 링크를 활성으로만 간주함
동적 라우팅
ProductsPage.jsx
import { Link } from "react-router-dom";
const PRODUCTS = [
{ id: "p1", title: "Product 1" },
{ id: "p2", title: "Product 2" },
{ id: "p3", title: "Product 3" },
];
function ProductsPage() {
return (
<>
<h1>Products Page</h1>
<ul>
{PRODUCTS.map((prod) => (
<li key={prod.id}>
<Link to={prod.id}>{prod.title}</Link>
</li>
))}
</ul>
</>
);
}
export default ProductsPage;
ProductsDetail.js
import { useParams } from "react-router-dom";
import { Link } from "react-router-dom";
function ProductDetailPage() {
const params = useParams();
return (
<>
<h1>Product Detail Page</h1>
<p>{params.productId}</p>
<p>
<Link to=".." relative="path">
Back
</Link>
</p>
</>
);
}
export default ProductDetailPage;
parameter 사용
useParams를 통해 가져올 수 있음
params.productId(productId는 라우터 path생성 당시 path에서 지정한 파라미터 이름 ex) products/:productId 라고지정했을 때 productId에 속함)
Link to=".." : 활성이었던 경로의 한단계 위의 라우트로 돌아가라는 의미, 부모 path로 돌아감
Link to=".." relative="path": 활성 중인 경로에서 한 세그먼트만 제거
절대경로
/로 시작
path가 항상 도메인 이름 뒤에서 부터 나타남
ex) path : "/"
ex) path : "/products"
상대경로
/를 빼고 시작
컴포넌트 내에서 상대경로를 입력하면
활성중인 경로 뒤에 경로가 추가 됨
'React' 카테고리의 다른 글
[React] Router , action, defer() (0) | 2024.04.30 |
---|---|
[React] router loader, useNavigation (0) | 2024.04.24 |
[React] Redux (0) | 2024.04.19 |
[React] Form Validation check (0) | 2024.04.18 |
[React] Custom Hook (0) | 2024.04.17 |