1. API 연동의 기본
- API 를 호출하기 위해서 axios 라는 라이브러리를 설치
yarn add axios
- axios를 사용해서 GET, PUT, POST, DELETE 등의 메서드로 API 요청을 할 수 있음
- GET: 데이터 조회
- POST: 데이터 등록
- PUT: 데이터 수정
- DELETE: 데이터 제거
import axios from 'axios';
axios.get('/users/1');
- get 이 위치한 자리에는 메서드 이름을 소문자로 넣음 - ex) 새로운 데이터를 등록하고 싶다면 axios.post() 를 사용
- 파라미터에는 API 의 주소를 넣음
- axios.post() 로 데이터를 등록 할 때에는 두번째 파라미터에 등록하고자 하는 정보를 넣을 수 있음
axios.post('/users', {
username: 'blabla',
name: 'blabla'
});
- 우리가 이번에 API 연동 실습을 할 때에는 JSONPlaceholder 에 있는 연습용 API 를 사용할 것
- 사용할 API 주소: https://jsonplaceholder.typicode.com/users
useState 와 useEffect 로 데이터 로딩하기
- useState 를 사용하여 요청 상태를 관리 & useEffect 를 사용하여 컴포넌트가 렌더링되는 시점에 요청을 시작
- 요청에 대한 상태를 관리 할 때에는 다음과 같이 총 3가지 상태를 관리
- 요청의 결과
- 로딩 상태
- 에러
// Users.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function Users() {
const [users, setUsers] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUsers = async () => {
try {
// 요청이 시작 할 때에는 error 와 users 를 초기화하고
setError(null);
setUsers(null);
// loading 상태를 true 로 바꿉니다.
setLoading(true);
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
setUsers(response.data); // 데이터는 response.data 안에 들어있습니다.
} catch (e) {
setError(e);
}
setLoading(false);
};
fetchUsers();
}, []);
if (loading) return <div>로딩중..</div>; // 로딩 상태가 활성화 됐을 때
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return null; // users 값이 아직 없을 때
return (
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
);
}
export default Users;
- useEffect 에 첫번째 파라미터로 등록하는 함수에는 async 를 사용 할 수 없기 때문에 함수 내부에서 async 를 사용하는 새로운 함수를 선언해주어야 함
- 맨 마지막에서는 users 배열을 렌더링하는 작업을 해줌
// App.js
import React from 'react';
import Users from './Users';
function App() {
return <Users />;
}
export default App;
버튼을 눌러서 API 재요청하기
- 아까 구현했던 fetchUsers 함수를 바깥으로 꺼내주고, 버튼을 만들어서 해당 함수를 연결
// Users.js
function Users() {
const [users, setUsers] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchUsers = async () => {
try {
// 요청이 시작 할 때에는 error 와 users 를 초기화하고
setError(null);
setUsers(null);
// loading 상태를 true 로 바꿉니다.
setLoading(true);
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
setUsers(response.data); // 데이터는 response.data 안에 들어있습니다.
} catch (e) {
setError(e);
}
setLoading(false);
};
useEffect(() => {
fetchUsers();
}, []);
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return null;
return (
<>
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={fetchUsers}>다시 불러오기</button>
</>
);
}
2. React Router v6 튜토리얼
라우팅이란?
- 웹 애플리케이션에서 라우팅이라는 개념은 사용자가 요청한 URL에 따라 알맞는 페이지를 보여주는 것을 의미
- 웹 애플리케이션을 만들때 프로젝트를 하나의 페이지로 구성할 수도 있고, 여러 페이지를 구성할 수 있음
ex) 로그를 만든다고 가정
- 글쓰기 페이지: 새로운 포스트를 작성하는 페이지
- 포스트 목록 페이지: 블로그에 작성된 여러 포스트들의 목록을 보여주는 페이지
- 포스트 읽기 페이지: 하나의 포스트를 보여주는 페이지
페이지별로 컴포넌트들을 분리해가면서 프로젝트를 관리하기 위해 필요한 것이 바로 라우팅 시스템
- 리액트에서 라우트 시스템을 구축하기위해 사용할 수 있는 선택지는 크게 두가지
- 리액트 라우터 (React Router): 리액트의 라우팅 관련 라이브러리들 중에서 가장 오래됐고, 가장 많이 사용 - 라이브러리는 컴포넌트 기반으로 라우팅 시스템을 설정할 수 있음
- Next.js: 리액트 프로젝트의 프레임워크 - 우리가 사용했던 Create React App처럼 리액트 프로젝트 설정을 하는 기능, 라우팅 시스템, 최적화, 다국어 시스템 지원, 서버 사이드 렌더링 등 다양한 기능들을 제공 - 이 프레임워크의 라우팅 시스템은 파일 경로 기반으로 작동 - 이 프레임워크는 리액트 라우터의 대안으로 많이 사용
- 라우팅 관련 기능을 리액트 라이브러리에서 공식적으로 지원하는 것이 아니라 써드 파티로서 제공 -> 이 외에도 react-location, rakkas 등의 프로젝트들이 존재
싱글 페이지 애플리케이션이란?
- 한 개의 페이지로 이루어진 애플리케이션이라는 의미
- 먼저 멀티 페이지 애플리케이션은 어떻게 작동하는지 알아야 함
멀티 페이지 애플리케이션에서는 사용자가 다른 페이지로 이동할 때마다 새로운 html을 받아오고, 페이지를 로딩할 때마다 서버에서 리소스를 전달받아 브라우저 화면에 보여줌
각 페이지마다 다른 html 파일을 만들어서 제공을 하거나, 데이터에 따라 유동적인 html을 생성해 주는 템플릿 엔진을 사용
=> 사용자 인터랙션이 많고 다양한 정보를 제공하는 모던 웹 애플리케이션은 이 방식이 적합 X
-> 리액트 같은 라이브러리를 사용해서 뷰 렌더링을 사용자의 브라우저가 담당하도록 하고, 우선 웹 애플리케이션을 브라우저에 불러와서 실행시킨 후에 사용자와의 인터랙션이 발생하면 필요한 부분만 자바스크립트를 사용하여 업데이트하는 방식을 사용 - 만약 새로운 데이터가 필요하다면 서버 API를 호출하여 필요한 데이터만 새로 불러와 애플리케이션에서 사용
- 이렇게 html은 한번만 받아와서 웹 애플리케이션을 실행시킨 후에 그 이후에는 필요한 데이터만 받아와서 화면에 업데이트 해주는 것이 싱글 페이지 애플리케이션
- 기술적으로는 한 페이지만 존재하는 것이지만, 사용자가 경험하기에는 여러 페이지가 존재하는 것 처럼 느껴짐
리액트 라우터 적용 및 기본 사용법
프로젝트 생성 및 라이브러리 설치
- 라우터를 설치할 때는 yarn 을 사용하여 react-router-dom이라는 라이브러리를 설치
yarn add react-router-dom
프로젝트에 라우터 적용
- 프로젝트에 리액트 라우터를 적용할 때는 src/index.js 파일에서 react-router-dom에 내장되어 있는 BrowserRouter라는 컴포넌트를 사용하여 감쌈
- 이 컴포넌트는 웹 애플리케이션에 HTML5의 History API를 사용하여 페이지를 새로 불러오지 않고도 주소를 변경하고 현재 주소의 경로에 관련된 정보를 리액트 컴포넌트에서 사용할 수 있도록 해줌
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
페이지 컴포넌트 만들기
- 리액트 라우터를 통해 여러 페이지로 구성된 웹 애플리케이션을 만들기 위하여 각 페이지에서 사용할 컴포넌트를 만듦
- 사용자가 웹 사이트에 들어오게 됐을 때 가장 먼저 보여지게 될 Home 페이지 컴포넌트와 웹 사이트를 소개하는 About 페이지 컴포넌트
// src/pages/Home.js
const Home = () => {
return (
<div>
<h1>홈</h1>
<p>가장 먼저 보여지는 페이지입니다.</p>
</div>
);
};
export default Home;
// src/pages/About.js
const About = () => {
return (
<div>
<h1>소개</h1>
<p>리액트 라우터를 사용해 보는 프로젝트입니다.</p>
</div>
);
};
export default About;
- 이 컴포넌트들을 꼭 pages 경로에 넣을 필요 X - 단순히 페이지를 위한 컴포넌트들을 다른 파일들과 구분하기 위함
Route 컴포넌트로 특정 경로에 원하는 컴포넌트 보여주기
- 사용자의 브라우저 주소 경로에 따라 우리가 원하는 컴포넌트를 보여주기 위해서 Route 라는 컴포넌트를 통해 라우트 설정
- Route 컴포넌는 다음과 같이 사용
<Route path="주소규칙" element={보여 줄 컴포넌트 JSX} />
- Route 컴포넌트는 Routes 컴포넌트 내부에서 사용
// src/App.js
import { Route, Routes } from 'react-router-dom';
import About from './pages/About';
import Home from './pages/Home';
const App = () => {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
);
};
export default App;
Link 컴포넌트를 사용하여 다른 페이지로 이동하는 링크 보여주기
- 웹 페이지에서는 원래 링크를 보여줄 때 a 태그를 사용 but 리액트 라우터를 사용하는 프로젝트에서 a 태그를 바로 사용 X: a 태그를 클릭하여 페이지를 이동할 때 브라우저에서는 페이지를 새로 불러오게 되기 때문
- Link 컴포넌트 역시 a 태그를 사용하긴 하지만, 페이지를 새로 불러오는 것을 막고 History API를 통해 브라우저 주소의 경로만 바꾸는 기능이 내장되어 있음
- Link 컴포넌트는 다음과 같이 사용합니다.
<Link to="경로">링크 이름</Link>
- Home 페이지에서 About 페이지로 이동할 수 있도록 Link 컴포넌트를 Home 페이지 컴포넌트에서 사용
// src/pages/Home.js
import { Link } from 'react-router-dom';
const Home = () => {
return (
<div>
<h1>홈</h1>
<p>가장 먼저 보여지는 페이지입니다.</p>
<Link to="/about">소개</Link>
</div>
);
};
export default Home;
URL 파라미터와 쿼리스트링
- 페이지 주소를 정의할 때 가끔은 유동적인 값을 사용해야 할 때도 있음
- URL 파라미터 예시: /profile/velopert
- 쿼리스트링 예시: /articles?**page=1&keyword=react
- URL 파라미터는 주소의 경로에 유동적인 값을 넣는 형태고, 쿼리 스트링은 주소의 뒷부분에 ? 문자열 이후에 key=value 로 값을 정의하며 & 로 구분을 하는 형태
- 주로 URL 파라미터는 ID 또는 이름을 사용하여 특정 데이터를 조회할 때 사용하고, 쿼리스트링(Querystring)은 키워드 검색, 페이지네이션, 정렬 방식 등 데이터 조회에 필요한 옵션을 전달할 때 사용
URL 파라미터
// src/pages/Profile.js
import { useParams } from 'react-router-dom';
const data = {
velopert: {
name: '김민준',
description: '리액트를 좋아하는 개발자',
},
gildong: {
name: '홍길동',
description: '고전 소설 홍길동전의 주인공',
},
};
const Profile = () => {
const params = useParams();
const profile = data[params.username];
return (
<div>
<h1>사용자 프로필</h1>
{profile ? (
<div>
<h2>{profile.name}</h2>
<p>{profile.description}</p>
</div>
) : (
<p>존재하지 않는 프로필입니다.</p>
)}
</div>
);
};
export default Profile;
- URL 파라미터는 useParams 라는 Hook을 사용하여 객체 형태로 조회 가능
- URL 파라미터의 이름은 라우트 설정을 할 때 Route 컴포넌트의 path props를 통하여 설정
// src/App.js
import { Route, Routes } from 'react-router-dom';
import About from './pages/About';
import Home from './pages/Home';
import Profile from './pages/Profile';
const App = () => {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profiles/:username" element={<Profile />} />
</Routes>
);
};
export default App;
- URL 파라미터는 /profiles/:username 과 같이 경로에 : 를 사용하여 설정
- 만약 URL 파라미터가 여러개인 경우엔 /profiles/:username/:field 와 같은 형태로 설정
쿼리스트링
- 쿼리스트링을 사용할 때는 URL 파라미터와 달리 Route 컴포넌트를 사용할 때 별도로 설정해야되는 것은 없음
// src/pages/About.js
import { useLocation } from 'react-router-dom';
const About = () => {
const location = useLocation();
return (
<div>
<h1>소개</h1>
<p>리액트 라우터를 사용해 보는 프로젝트입니다.</p>
<p>쿼리스트링: {location.search}</p>
</div>
);
};
export default About;
- 위 컴포넌트에서 useLocation 이라는 Hook을 사용 - 이 Hook은 location 객체를 반환하며 이 객체는 현재 사용자가 보고있는 페이지의 정보를 지니고 있음
- 이 객체에는 다음과 같은 값들이 있음
- pathname: 현재 주소의 경로 (쿼리스트링 제외)
- search: 맨 앞의 ? 문자 포함한 쿼리스트링 값
- hash: 주소의 # 문자열 뒤의 값 (주로 History API 가 지원되지 않는 구형 브라우저에서 클라이언트 라우팅을 사용할 때 쓰는 해시 라우터에서 사용합니다.)
- state: 페이지로 이동할때 임의로 넣을 수 있는 상태 값
- key: location 객체의 고유 값, 초기에는 default 이며 페이지가 변경될때마다 고유의 값이 생성됨
- 쿼리스트링은 location.search 값을 통해 조회 가능
- 주소창에 http://localhost:3000/about?detail=true&mode=1 라고 직접 입력해서 값 확인 가능
- 리액트 라우터에서는 v6부터 useSearchParams 라는 Hook을 통해서 쿼리스트링을 더욱 쉽게 다룰 수 있움
// src/pages/About.js
import { useSearchParams } from 'react-router-dom';
const About = () => {
const [searchParams, setSearchParams] = useSearchParams();
const detail = searchParams.get('detail');
const mode = searchParams.get('mode');
const onToggleDetail = () => {
setSearchParams({ mode, detail: detail === 'true' ? false : true });
};
const onIncreaseMode = () => {
const nextMode = mode === null ? 1 : parseInt(mode) + 1;
setSearchParams({ mode: nextMode, detail });
};
return (
<div>
<h1>소개</h1>
<p>리액트 라우터를 사용해 보는 프로젝트입니다.</p>
<p>detail: {detail}</p>
<p>mode: {mode}</p>
<button onClick={onToggleDetail}>Toggle detail</button>
<button onClick={onIncreaseMode}>mode + 1</button>
</div>
);
};
export default About;
- useSearchParams 는 배열 타입의 값을 반환하며, 첫번째 원소는 쿼리파라미터를 조회하거나 수정하는 메서드들이 담긴 객체를 반환
- get 메서드를 통해 특정 쿼리파라미터를 조회할 수 있고, set 메서드를 통해 특정 쿼리파라미터를 업데이트 할 수 있음
- 만약 조회시에 쿼리파라미터가 존재하지 않는다면 null 로 조회
- 두번째 원소는 쿼리파라미터를 객체형태로 업데이트할 수 있는 함수를 반환
- 쿼리파라미터를 사용할 때 주의할 점은 쿼리파라미터를 조회할 때 값은 무조건 문자열 타입이라는 것
- true 또는 false 값을 넣게 된다면 값을 비교할 때 꼭 'true' 와 같이 따옴표로 감싸서 비교
- 숫자를 다루게 된다면 parseInt 를 사용하여 숫자 타입으로 변환
중첩된 라우트
// src/pages/Articles.js
import { Link } from 'react-router-dom';
const Articles = () => {
return (
<ul>
<li>
<Link to="/articles/1">게시글 1</Link>
</li>
<li>
<Link to="/articles/2">게시글 2</Link>
</li>
<li>
<Link to="/articles/3">게시글 3</Link>
</li>
</ul>
);
};
export default Articles;
// src/App.js: 라우트 설정
import { Route, Routes } from 'react-router-dom';
import About from './pages/About';
import Article from './pages/Article';
import Articles from './pages/Articles';
import Home from './pages/Home';
import Profile from './pages/Profile';
const App = () => {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profiles/:username" element={<Profile />} />
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
</Routes>
);
};
export default App;
// src/pages/Home.js: 게이글 목록 페이지로 가는 링크 추가
import { Link } from 'react-router-dom';
const Home = () => {
return (
<div>
<h1>홈</h1>
<p>가장 먼저 보여지는 페이지입니다.</p>
<ul>
<li>
<Link to="/about">소개</Link>
</li>
<li>
<Link to="/profiles/velopert">velopert의 프로필</Link>
</li>
<li>
<Link to="/profiles/gildong">gildong의 프로필</Link>
</li>
<li>
<Link to="/profiles/void">존재하지 않는 프로필</Link>
</li>
<li>
<Link to="/articles">게시글 목록</Link>
</li>
</ul>
</div>
);
};
export default Home;
- Articles 컴포넌트에서 리액트 라우터에서 제공하는 Outlet 이라는 컴포넌트를 사용
- 이 컴포넌트는 Route 의 children 으로 들어가는 JSX 엘리먼트를 보여주는 역할
<Route path=":id" element={<Article />} />
// src/pages/Articles.js
import { Link, Outlet } from 'react-router-dom';
const Articles = () => {
return (
<div>
<Outlet />
<ul>
<li>
<Link to="/articles/1">게시글 1</Link>
</li>
<li>
<Link to="/articles/2">게시글 2</Link>
</li>
<li>
<Link to="/articles/3">게시글 3</Link>
</li>
</ul>
</div>
);
};
export default Articles;
공통 레이아웃 컴포넌트
- 중첩된 라우트와 Outlet 은 페이지끼리 공통적으로 보여줘야 하는 레이아웃이 있을때도 유용하게 사용할 수 있음
ex) Home, About, Profile 페이지에서 상단에 헤더를 보여줘야 하는 상황을 가정
첫 번째로 드는 생각은 아마 Header 컴포넌트를 따로 만들어두고 각 페이지 컴포넌트에서 재사용을 하는 방법
중첩된 라우트를 사용하는 방식을 사용하면 컴포넌트를 한번만 사용해도 된다는 장점 - 상황에 따라 그리고 취향에 따라 구현
- 공통 레이아웃을 위한 Layout 컴포넌트
// src/Layout.js
import { Outlet } from 'react-router-dom';
const Layout = () => {
return (
<div>
<header style={{ background: 'lightgray', padding: 16, fontSize: 24 }}>
Header
</header>
<main>
<Outlet />
</main>
</div>
);
};
export default Layout;
- 각 페이지 컴포넌트가 보여져야 하는 부분에 Outlet 컴포넌트를 사용
// src/App.js
import { Route, Routes } from 'react-router-dom';
import Layout from './Layout';
import About from './pages/About';
import Article from './pages/Article';
import Articles from './pages/Articles';
import Home from './pages/Home';
import Profile from './pages/Profile';
const App = () => {
return (
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profiles/:username" element={<Profile />} />
</Route>
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
</Routes>
);
};
export default App;
index props
- Route 컴포넌트에는 index 라는 props가 있습니다. 이 props 는 path="/"와 동일한 의미
// src/App.js
import { Route, Routes } from 'react-router-dom';
import Layout from './Layout';
import About from './pages/About';
import Article from './pages/Article';
import Articles from './pages/Articles';
import Home from './pages/Home';
import Profile from './pages/Profile';
const App = () => {
return (
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profiles/:username" element={<Profile />} />
</Route>
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
</Routes>
);
};
export default App;
- index prop은 상위 라우트의 경로와 일치하지만, 그 이후에 경로가 주어지지 않았을때 보여지는 라우트를 설정할때 사용
- path="/"와 동일한 역할을 하며 이를 좀 더 명시적으로 표현하는 방법
리액트 라우터 부가기능
- 리액트 라우터에는 웹 애플리케이션에서 라우팅에 관련된 작업을 할 때 사용할 수 있는 유용한 API들을 제공
useNavigate
- Link 컴포넌트를 사용하지 않고 다른 페이지로 이동을 해야 하는 상황에 사용하는 Hook
src/Layout.js
import { Outlet, useNavigate } from 'react-router-dom';
const Layout = () => {
const navigate = useNavigate();
const goBack = () => {
// 이전 페이지로 이동
navigate(-1);
};
const goArticles = () => {
// articles 경로로 이동
navigate('/articles');
};
return (
<div>
<header style={{ background: 'lightgray', padding: 16, fontSize: 24 }}>
<button onClick={goBack}>뒤로가기</button>
<button onClick={goArticles}>게시글 목록</button>
</header>
<main>
<Outlet />
</main>
</div>
);
};
export default Layout;
- navigate 함수를 사용할 때 파라미터가 숫자 타입이라면 앞으로 가거나, 뒤로 감
ex) navigate(-1) 을 하면 한 번 뒤로, navigate(-2) 를 하면 두 번 뒤로, navigate(1) 을 하면 앞으로 한 번
- 다른 페이지로 이동을 할 때 replace 라는 옵션 - 이 옵션을 사용하면 페이지를 이동할 때 현재 페이지를 페이지 기록에 남김 X
// src/Layout.js - goArticles
const goArticles = () => {
navigate('/articles', { replace: true });
}
- 만약 { replace: true } 설정이 없었더라면 직전에 봤던 페이지인 About 페이지가 나타나야 하지만, 이 옵션이 활성화되어있기 때문에, 그 전의 페이지인 Home 페이지가 나타남
NavLink
- NavLink 컴포넌트는 링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 스타일 또는 CSS 클래스를 적용하는 컴포넌트
- 이 컴포넌트를 사용할 때 style 또는 className을 설정할 때 { isActive: boolean } 을 파라미터로 전달받는 함수 타입의 값을 전달
<NavLink
style={({isActive}) => isActive ? activeStyle : undefined}
/>
<NavLink
className={({isActive}) => isActive ? 'active' : undefined}
/>
// src/pages/Articles.js
import { NavLink, Outlet } from 'react-router-dom';
const Articles = () => {
return (
<div>
<Outlet />
<ul>
<ArticleItem id={1} />
<ArticleItem id={2} />
<ArticleItem id={3} />
</ul>
</div>
);
};
const ArticleItem = ({ id }) => {
const activeStyle = {
color: 'green',
fontSize: 21,
};
return (
<li>
<NavLink
to={`/articles/${id}`}
style={({ isActive }) => (isActive ? activeStyle : undefined)}
>
게시글 {id}
</NavLink>
</li>
);
};
export default Articles;
- 현재 NavLink 를 감싼 또 다른 컴포넌트를 만들어서 다음과 같이 리팩토링하여 사용하시는 것을 권장
NotFound 페이지 만들기
- 이 페이지는 사전에 정의되지 않는 경로에 사용자가 진입했을 때 보여주는 페이지 - 페이지를 찾을 수 없을 때 나타나는 페이지
// src/pages/NotFound.js
const NotFound = () => {
return (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 64,
position: 'absolute',
width: '100%',
height: '100%',
}}
>
404
</div>
);
};
export default NotFound;
// src/App.js
import { Route, Routes } from 'react-router-dom';
import Layout from './Layout';
import About from './pages/About';
import Article from './pages/Article';
import Articles from './pages/Articles';
import Home from './pages/Home';
import NotFound from './pages/NotFound';
import Profile from './pages/Profile';
const App = () => {
return (
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profiles/:username" element={<Profile />} />
</Route>
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
);
};
export default App;
- * 는 wildcard 문자: 아무 텍스트나 매칭한다는 뜻
- 이 라우트 엘리먼트의 상단에 위치하는 라우트들의 규칙을 모두 확인하고, 일치하는 라우트가 없다면 이 라우트가 화면에 나타남
Navigate 컴포넌트
- Navigate 컴포넌트는 컴포넌트를 화면에 보여주는 순간 다른 페이지로 이동을 하고 싶을 때 사용하는 컴포넌트 - 페이지를 리다이렉트 하고 싶을 때 사용 ex)
사용자의 로그인이 필요한 페이지인데 로그인을 안했다면 로그인 페이지를 보여주어야 함
// src/pages/Login.js
const Login = () => {
return <div>로그인 페이지</div>;
};
export default Login;
// src/pages/MyPage.js
import { Navigate } from 'react-router-dom';
const MyPage = () => {
const isLoggedIn = false;
if (!isLoggedIn) {
return <Navigate to="/login" replace={true} />;
}
return <div>마이 페이지</div>;
};
export default MyPage;
- 여기서 isLoggedIn은 현재 false라는 고정값을 가지고 있지만, 이 값이 로그인 상태에 따라 true 또는 false를 가르킨다고 가정
- 위 컴포넌트에서는 만약 이 값이 false 라면 Navigate 컴포넌트를 통해 /login 경로로 이동
- 여기서 replace props는 useNavigate 에서 설명한 것과 동일
- 페이지를 이동할 때 현재 페이지를 기록에 남기지 않기 때문에 이동 후 뒤로가기를 눌렀을 때 2 페이지 전의 페이지로 이동
// src/App.js
import { Route, Routes } from 'react-router-dom';
import Layout from './Layout';
import About from './pages/About';
import Article from './pages/Article';
import Articles from './pages/Articles';
import Home from './pages/Home';
import Login from './pages/Login';
import MyPage from './pages/MyPage';
import NotFound from './pages/NotFound';
import Profile from './pages/Profile';
const App = () => {
return (
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profiles/:username" element={<Profile />} />
</Route>
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
<Route path="/login" element={<Login />} />
<Route path="/mypage" element={<MyPage />} />
<Route path="*" element={<NotFound />} />
</Routes>
);
};
export default App;
'WINK-(Web & App) > React.js 스터디' 카테고리의 다른 글
[2024 여름방학 React.js 스터디] 김태일 #1주차 - 자바스크립트 입문 (0) | 2024.07.10 |
---|---|
[2024 React.js 스터디] 류상우 #7주차 (0) | 2024.07.07 |
[2024 React.js 스터디] 정호용 #마지막주차 "API와 라우터" (0) | 2024.06.27 |
[2024 React.js 스터디] 김지나 #7주차 (0) | 2024.06.02 |
[2024 React.js 스터디] 이서영 #6주차 (0) | 2024.05.28 |