- React는 모든 것을 component단위로 만들고 코드를 관리한다.
- 복잡한 페이지를 component로 쪼개로 개발하면 빠르고, 쉽고, 여럿이 동시에 만들 수 있는 장점이 있다.
- React에서는 이 component단위로 화면을 이동시킬 수 있다.
- HTML에서는 화면을 이동할 때, 다른 HTML파일로의 이동만이 가능했던 점이 다르다.
React Router v6
npm install react-router-dom@6
- React Component로 페이지를 나누고, 이동할 수 있게 해주는 라이브러리이다.
- 위 명령어로 설치한다.
<Routes>
<Route path="/" element={<HomePage/>} />
<Route path="courses/" element={<CourseListPage/>} />
<Route path="courses/1" element={<CoursePage/>} />
<Route path="*" element={<NotFoundPage/>} />
</Routes>
- 위와같이 컴포넌트단위로 페이지를 나눈다.
<Link to="/">홈페이지</Link>
<Link to="/courses">수업탐색</Link>
<Link to="/question">커뮤니티</Link>
- 그리고 이렇게 페이지를 이동시킬 수 있다.
React Router의 핵심 컴포넌트
1. Router
- React Router에서 사용하는 모든 데이터(현재 주소, 페이지 기록 등)를 가지고 있다.
- Router가 없으면 React Router를 쓸 수 없다.
- Router컴포넌트는 내부적으로 context.provider와 같기때문에, React Router의 기능을 사용하기위해서는 반드시 Router 컴포넌트 안에서 사용해야한다.
- 보통 최상위 컴포넌트를 Router로 감싸서 프로젝트 전체에서 React Router를 사용할 수 있게 만든다.
2. Routes, Route
<Routes>
<Route path="/" element={<HomePage/>} />
<Route path="courses/" element={<CourseListPage/>} />
<Route path="courses/1" element={<CoursePage/>} />
<Route path="*" element={<NotFoundPage/>} />
</Routes>
- switch - case 문과 같이 url이 들어오면, 위에서부터 하나씩 검사한다.
- path와 url이 일치하면, 해당 Route의 element prop의 컴포넌트로 이동한다.
- Route 컴포넌트는 Routes 컴포넌트 내부에 사용해야한다.
- Routes 컴포넌느 내부에는 Route 컴포넌트만 사용할 수 있다.
3. Link
React Router에서 a태그 대신 사용하는 컴포넌트로, 페이지를 이동시킬 수 있다.
<Link to="/">홈페이지</Link>
<Link to="/courses">수업탐색</Link>
<Link to="/question">커뮤니티</Link>
Routes로 페이지 나누기
function Main() {
return (
<BrowserRouter>
<App>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="courses" element={<CourseListPage />} />
<Route
path="courses/react-frontend-development"
element={<CoursePage />}
/>
<Route path="wishlist" element={<WishlistPage />} />
</Routes>
</App>
</BrowserRouter>
);
}
- "/" 경로로 들어오면, HomePage 컴포넌트가 렌더링된다.
- path prop으로 경로를 지정하고, element prop으로 보여줄 컴포넌트를 지정한다.
- element prop에는 컴포넌트 함수가 아닌, jsx를 넘겨줘야한다는 점을 기억하자.
- Routes컴포넌트는 이렇게 여러개의 Route를 포함한다.
- Route를 렌더링 할 때, 리액트는 Routes안에 있는 Route를 순서대로 검사한다.
- 일치하는 경로를 찾으면, element prop으로 지정한 컴포넌트를 렌더링한다.
- 여기서 Routes, Route는 react fragment처럼 아무 dom도 가지지않는다.
Link로 페이지 이동하기
import { Link } from 'react-router-dom';
function Nav() {
return (
<div className={styles.nav}>
<Container className={styles.container}>
<Link to="/">
<img src={logoImg} alt="Codethat Logo" />
</Link>
<ul className={styles.menu}>
<li>
<Link to="/courses">카탈로그</Link>
</li>
<li>커뮤니티</li>
<li>
<UserMenu />
</li>
</ul>
</Container>
</div>
);
}
- Link 를 import하고, 클릭시 페이지를 이동시켜야겠다고 생각한 노드를 Link컴포넌트로 감싸서 사용한다.
- Link컴포넌트는 to 라는 pro에 이동시킬 경로를 지정해줄 수 있다.
- 위 예시코드에서는 <Link to="/courses"> 라고 작성된 부분이 있는데, 맨 앞에 "/"를 붙여준 것은 절대경로라는 의미이다.
- 맨 앞에 "/"를 붙여주지않으면, 웹브라우저가 현재주서의 맨 끝에 "/courses" 를 붙인 곳으로 이동시키려한다.
<Link to={`/courses/${course.slug}`}>{course.title}</Link>
- 위와같이 템플릿문자열을 사용해서 to prop의 값을 적어줄 수 있다.
navLink로 네비게이션 구현하기
- Navigation Link 로, 메뉴에서 사용하는 Link라는 뜻이다.
- Link와, navLink의 차이점은 navLink는 style prop으로 함수를 지정해줄 수 있다는 점이다.
- NavLink의 style prop으로 지정된 함수는 불린타입의 값을 파라미터로 받는데, 이 값은 '현재 위치해있는 페이지의 경로가 해당 navLink의 path 경로와 같은지' 에대한 불린값이다.
- 그러니까, 해당 메뉴에 내가 들어와있다면 그 navLink를 어떤 스타일로 보여줄지를 함수 안에 적을 수 있다.
- 이 함수는 react inline style객체를 리턴하면 되고 아래와같이 만들 수 있다.
function getLinkStyle({ isActive }) {
return {
textDecoration: isActive ? 'underline' : undefined,
};
}
function Nav() {
return (
<div className={styles.nav}>
<Container className={styles.container}>
<Link to="/">
<img src={logoImg} alt="Codethat Logo" />
</Link>
<ul className={styles.menu}>
<li>
<NavLink to="/courses" style={getLinkStyle}>
카탈로그
</NavLink>
</li>
<li>
<NavLink to="/questions" style={getLinkStyle}>
커뮤니티
</NavLink>
</li>
<li>
<UserMenu />
</li>
</ul>
</Container>
</div>
);
}
하위 페이지 나누기
- Route로 페이지를 나누는 것이 복잡한 경우, Route를 중첩해서 코드를 조금 줄일 수 있다.
function Main() {
return (
<BrowserRouter>
<App>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="courses">
<Route index element={<CourseListPage />} />
<Route path="react-frontend-development" element={<CoursePage />} />
</Route>
<Route path="wishlist" element={<WishlistPage />} />
<Route path="questions" element={<QuestionListPage />} />
<Route path="questions/*" element={<QuestionPage />} />
</Routes>
</App>
</BrowserRouter>
);
}
- 상위 Route의 path에 "courses"를 주었기때문에, 하위 Route들의 path의 앞에는 "courses"가 생략되었다.
- 그리고 상위 Route의 path로 접근시 바로 보여줄 Route는 path가 아닌, index 를 prop으로 준다.
Outlet 컴포넌트
하위 Route 여러개에서 공통된 디자인을 보여주고 싶을 때(공통된 레이아웃을 지정해주고 싶을 때) 사용한다.
function App() {
return (
<>
<Nav className={styles.nav} />
<div className={styles.body}>
<Outlet />
</div>
<Footer className={styles.footer} />
</>
);
}
function Main() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route index element={<HomePage />} />
<Route path="courses">
<Route index element={<CourseListPage />} />
<Route path="react-frontend-development" element={<CoursePage />} />
</Route>
<Route path="wishlist" element={<WishlistPage />} />
<Route path="questions" element={<QuestionListPage />} />
<Route path="questions/*" element={<QuestionPage />} />
</Route>
</Routes>
</BrowserRouter>
);
}
- Main함수의 상위 Route컴포넌트의 element prop으로 App컴포넌트를 주고있다.
- App 컴포넌트에서는, Outlet 컴포넌트를 div에 넣고있다.
- App컴포넌트의 안에 Routes컴포넌트를 넣은거랑 뭐가 다른지 잘 모르겠다. 찾아보자.
useParams 로 동적인 경로 만들기
function Main() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route index element={<HomePage />} />
<Route path="courses">
<Route index element={<CourseListPage />} />
{/* 이 부분 */}
<Route path="react-frontend-development" element={<CoursePage />} />
</Route>
<Route path="wishlist" element={<WishlistPage />} />
<Route path="questions">
<Route index element={<QuestionListPage />} />
<Route path="*" element={<QuestionPage />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
);
}
위 코드의 Route path를 동적으로 만들어볼것이다.
function Main() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route index element={<HomePage />} />
<Route path="courses">
<Route index element={<CourseListPage />} />
{/* 이 부분 */}
<Route path=":courseSlug" element={<CoursePage />} />
</Route>
<Route path="wishlist" element={<WishlistPage />} />
<Route path="questions">
<Route index element={<QuestionListPage />} />
<Route path="*" element={<QuestionPage />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
);
}
- 위와 같이 작성하면, courseSlug라는 변수로 페이지의 경로를 받아올 수 있다.
- React Router에서는 이 것을 파라미터라고 부른다.
function CoursePage() {
/* 이 부분 */
const { courseSlug } = useParams();
const navigate = useNavigate();
const course = getCourseBySlug(courseSlug);
const courseColor = getCourseColor(course?.code);
...
}
- CoursePage 컴포넌트에서는 useParams를 사용해서 파라미터를 받을 수 있다.
- useParams는 현재 경로의 파라미터들이 저장되어있는 객체이다.
- Main에서 사용한 courseSlug라는 변수명(내가 임의로 정한 이름이다.)을 따라서 coursePage에서 꺼내볼 수 있다.
없는 페이지 처리
function Main() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route index element={<HomePage />} />
<Route path="courses">
<Route index element={<CourseListPage />} />
<Route path=":courseSlug" element={<CoursePage />} />
</Route>
<Route path="wishlist" element={<WishlistPage />} />
<Route path="questions">
<Route index element={<QuestionListPage />} />
<Route path=":questionId" element={<QuestionPage />} />
</Route>
<Route path="*" element={<NotFoundPage />} />
</Route>
</Routes>
</BrowserRouter>
);
}
- Route는 위에서부터 차례대로 검사를 시작한다고 했으니, 맨 마지막에 path="*" 을 가진 Route를 추가해주므로 존재하지 않는 url을 입력할 시, NotFoundPage 컴포넌트를 렌더링시킬 수 있다.
navigate로 리다이렉트하기
어떤 이유로, 다른페이지로 이동시키는 것을 redirect라고 부른다.
if (!course) {
return <Navigate to="/courses" />;
}
- 이렇게 사용할 수 있는데, Navigate컴포넌트가 렌더링되면 React Router는 to prop에 지정된 경로로 이동시켜준다.
useSearchParams로 쿼리 사용하기
const [searchParams, setSearchParams] = useSearchParams();
const initKeyword = searchParams.get('keyword');
- useSearchParams는, React Router에서 제공하는 커스텀훅이다.
- React Router에서 쿼리파라미터의 값을 가져오고 싶을 때 이 훅을 사용할 수 있다.
useNavigate로 페이지 이동하기
- 위에서 <Navigate> 컴포넌트를 리턴하면, React Router가 해당 컴포넌트를 렌더링할 때 지정된 경로로 이동한다고 배웠다.
- 만약 return문에서가 아닌 경우(렌더링하는 도중에 이동시킬 것이 아닌 경우) 코드상으로 페이지를 이동시키고 싶다면 useNavigate 훅을 사용할 수 있다.
import { Navigate, useParams, useNavigate } from 'react-router-dom';
...
function CoursePage() {
const navigate = useNavigate();
const handleAddWishlistClick = () => {
addWishlist(course?.slug);
navigate('/wishlist');
};
return (
<>
<div className={styles.header} style={headerStyle}>
...
<Button variant="round" onClick={handleAddWishlistClick}>
+ 코스 담기
</Button>
...
</div>
</>
);
}
export default CoursePage;
Link, Navigate, useNavigate 의 차이
Link
- 사용자가 클릭해서 페이지를 이동할 때 사용한다.
- 하이퍼링크 텍스트, 페이지 이동버튼, 이미지 등에 사용한다.
Navigate
- 특정 경로에서 렌더링시점에 다른 페이지로 이동시키고 싶을 때 사용한다.
- 쇼핑몰에서 회원전용 페이지에 로그인 없이 접근시, 로그인페이지로 redirect시킬 때
useNavigate
- 특정코드의 실행이 끝나고 페이지를 이동시키고 싶을 때 사용한다.
- 쇼핑몰의 장바구니에 담기버튼클릭으로 리퀘스트를 보낸 후 페이지를 이동시킬 때
- 결제버튼을 누르고 모든 결제가 완료된 후 페이지를 이동시킬 때
- 리다이렉트된 로그인 페이지에서 로그인을 완료한 후, 처음 진입했던 페이지로 이동시킬 때
'React' 카테고리의 다른 글
React - 생명주기(life cycle) (0) | 2023.10.29 |
---|---|
React - 리액트를 렌더링하는 방식에 대해(CSR, SPA 등) (0) | 2023.10.25 |
React - 배열을 렌더링시 key를 써야 하는 이유 (0) | 2023.10.23 |
React - Virtual DOM (0) | 2023.10.23 |
React - 데이터 다루기 (0) | 2023.10.20 |