📌 SPA란 ? (single page application)
SPA는 하나의 페이지로 만들어진 어플리케이션을 의미합니다. html파일을 브라우저 측에서 로드하고, 필요한 데이터는 API와 ajax 통신을 통해서 처리합니다. 브라우저에서 사용자가 상호작용하면 필요한 부분만 업데이트해서 처리하게 됩니다. 또한 멀티플랫폼 Android, IOS에 대응하여 웹뷰로 처리하는 목적으로도 사용됩니다.
하지만 SPA에도 단점이 존재합니다 🥹
앱의 규모가 커지면 JS파일도 너무 커져서 로딩이 오래 걸리게 됩니다. 그로 인해 브라우저에서 렌더링이 완료되기까지 빈 화면이 나오게 됩니다.
따라서 규모가 큰 어플리케이션은 SSR(서버사이드 렌더링) 방식으로 처리합니다. (웹팩 설정 필요)
📌 라우팅이란 ?
라우팅은 브라우저의 주소 상태에 따라 다양한 화면을 보여주도록 처리하는 것입니다. create-react-app으로 프로젝트를 생성하게 되면 기본적으로 SPA에 CSR(클라이언트 렌더링)이고 하나의 페이지만 사용하게 되는 것입니다. SPA이지만 라우터를 활용하면 사용자로 하여금 여러 페이지가 존재하는 것처럼 느껴지게 할 수 있습니다.
자, 그러면 라우터를 설치하고 프로젝트를 시작해봅시다 !
⓵ 라우터를 적용할 프로젝트 생성
npm create react-app 프로젝트명
⓶ 라우터 설치
npm install react-router-dom
⓷ 프로젝트 시작
npm start
📌 라우터 적용하기
라우터를 사용할 때에는 index.js에서 App컴포넌트를 <BrowserRouter>으로 감싸주어야합니다.
📍 App.js
import { Route } from "react-router-dom";
function App() {
return (
<Routes>
<Route path='/' element={<Home/>}/>
<Route path='/user' element={<User/>}/>
<Route path='/info' element={<Info/>}/>
</Routes>
)
}
export default App;
/ 요청은 Home컴포넌트, / user 요청은 User컴포넌트, / info 요청은 Info컴포넌트가 나타나게 됩니다.
📌 Link를 이용해서 다른 페이지로 이동하기
link 태그는 화면에서 a태그로 생성되는데 to 속성에는 연결할 요청주소를 적습니다. 이는 어느 컴포넌트에서든 사용할 수 있습니다.
//📍--- Home.js (/로 연결되는 컴포넌트)
import { Link } from "react-router-dom";
function Home() {
return (
<div>
<h3>홈페이지입니다</h3>
<Link to='/user'>user페이지</Link> //--- user페이지 연결
</div>
)
}
export default Home;
📌 쿼리스트링( &키=값 ) 또는 URL파라미터( /경로/값/값 ) 활용하기
같은 컴포넌트라도 전달되는 데이터에 따라서 다른 내용을 보여주어야하는 경우가 있습니다. 이러한 경우에 URL주소의 매개변수를 전달할 수 있고 컴포넌트는 그 값을 받아서 사용할 수 있습니다.
⓵ 쿼리스트링
쿼리스트링은 주소의 ? 뒤에 키=값의 형태로 전달하는 매개값입니다. 별도의 라우터 설정은 하지 않아도 되며, 컴포넌트에서는 useLocation( ) 훅 혹은 useSearchParams( ) 훅을 사용해서 쿼리스트링을 받을 수 있습니다.
//... return (
<ul>
<li>
<Link to='/user?name=뉴진스&age=20'>회원페이지</Link>
</li>
</ul>
)
이제 연결된 User.js을 살펴보겠습니다.
import { useSearchParams } from "react-router-dom";
function User() {
//--- useSearchParams() hook을 사용합니다.
const [obj, setObj] = useSearchParams();
// console.log(obj); //--- 값을 얻을 수 있습니다.
// console.log(setObj); //--- URI값을 얻을 수 있습니다.
let name = obj.get("name"); //--- name키를 얻을 수 있습니다.
let age = obj.get("age"); //--- age키를 얻을 수 있습니다.
const handleClick = () => {
setObj({name: '뉴진스2', age: 21}); //--- 파라미터값을 변경합니다.
}
return (
<div>
<h3>유저페이지입니다</h3>
<button onClick={handleClick}>URI값 변경</button>
</div>
)
}
export default User;
⓶ URL파라미터
URL파라미터는 주소 뒤에 /경로/값/값 의 형태로 전달하는 매개값입니다. 라우터에 추가적인 설정( /주소/:키 )의 설정이 필요하며, 컴포넌트에서는 useParams( ) 훅을 사용하여 URL파라미터를 받을 수 있습니다.
import { Route } from "react-router-dom";
function App() {
return (
<Routes>
<Route path='/info/:num' element={<Info/>}/>
</Routes>
)
}
export default App;
이제 연결된 Info.js을 살펴보겠습니다.
import { useParams } from "react-router-dom";
function Info() {
//--- 임의의 예시 데이터입니다.
const data = {
"1" : {id:1, name: "해린"},
"2" : {id:2, name: "하니"},
"3" : {id:3, name: "혜인"}
}
//--- useParams hook은 URL파라미터를 받습니다.
let param = useParams(); //--- param에는 link로 넘어온 키가 담겨있습니다.
console.log(param.num); //--- 키값인 num을 찾아줍니다.
//--- param의 키값num에 맞는 data의 id와 name값을 저장합니다.
const {id, name} = data[param.num];
return (
<div>
<h3>Info페이지입니다</h3>
<div>{id}이고 {name}입니다</div>
</div>
)
}
export default Info;
✔︎ 중첩 라우터로 공통 부분 처리하기
글페이지와 글에 따른 상세화면이 있다고 가정하고 라우터 설정을 해봅시다. 아래 설정은 두 라우터가 다르기 때문에 각각 다른 화면이 보입니다.
<Routes>
<Route path='/board' element={<Board/>}/>
<Route path='/board/:num' element={<BoardContent/>}/>
</Routes>
여기서! 만약 Board목록 페이지를 공통으로 사용하고 상세페이지를 서브로 보여주도록 처리하고자 한다면 중첩라우터를 사용할 수 있습니다.
중첩 라우터로 적용되면 부모컴포넌트에서 <Outlet> 컴포넌트를 활용해서 하위 라우터를 보여지게 할 수 있습니다.
<Routes>
<Route path='/board' element={<Board/>}>
<Route path=':num' element={<BoardContent/>}/>
</Route>
</Routes>
이런 식으로 부모컴포넌트(Board), 자식컴포넌트(BoardContent)로 지정할 수 있습니다.
📍--- Board.js
import { Link, Outlet } from "react-router-dom";
function Board() {
return (
<>
<h3>글 목록</h3>
<ul>
{
<li><Link to='/board/1'>1번글</Link></li>
<li><Link to='/board/2'>2번글</Link></li>
<li><Link to='/board/3'>3번글</Link></li>
}
</ul>
{/* 중첩라우터에서 하위컴포넌트를 표시합니다 */}
<Outlet/>
</>
)
}
export default Board;
📍--- BoardContent.js
import { useParams } from "react-router-dom";
function BoardContent() {
const {num} = useParams(); //--- param의 키값으로 num을 가져옵니다.
return (
<>
<h3>글 상세</h3>
{num}번 글입니다.
</>
)
}
export default BoardContent;
이런 화면이 나온다면 성공입니다🙆🏻♀️
✔︎ NavLink컴포넌트 ( = Link컴포넌트)
NavLink는 링크의 경로가 라우터의 경로와 일치하면 특정 스타일을 적용해주는 기능으로 style 속성을 제공합니다. style 속성에는 실행시킬 함수를 작성하는데 이 함수에 매개변수로 { isActive : boolean } 객체를 넣어주게 되고 활성화 여부를 표시할 수 있어집니다. 사용은 반드시 { isActive } 변수로 구조분해할당합니다.
import { NavLink, Outlet } from "react-router-dom";
function Board() {
const myStyle = {color: "green", backgroundColor: "yellow"};
return (
<>
<ul>
<h3>글 목록</h3>
<li><NavLink to='/board/1' style={({isActive}) => {
return isActive ? myStyle : undefined;
}}>1번글</NavLink></li>
<li><NavLink to='/board/2' style={({isActive}) => isActive ? myStyle : undefined }>2번글</NavLink></li>
<li><NavLink to='/board/3' style={({isActive}) => isActive ? myStyle : undefined }>3번글</NavLink></li>
</ul>
{/* 중첩라우터에서 하위컴포넌트를 표시한다 */}
<Outlet/>
</>
)
}
export default Board;
✔︎ useNavigate( ) 훅
useNavigate 훅은 특정 이벤트가 발생할 때, url을 조작할 수 있는 함수를 제공합니다.
import { Navigate, useNavigate } from "react-router-dom";
function MyPage() {
//권한 검사 : 렌더링 과정에는 사용이 불가능
// let nav = useNavigate();
let loginYN = false; //로그인 처리에 대한 내역을 관리하는 값
if(!loginYN) {
// nav('/');
return <Navigate to='/' replace={true}/> //history를 남기지 않음
}
return(
<>
<h3>권한이 있는 유저만 접근이 가능한 화면</h3>
</>
)
}
export default MyPage;
📍--- Header.js
import { Outlet, useNavigate } from 'react-router-dom';
import style from './Header.module.css';
function Header() {
//useNavigate hook : history객체를 대신합니다.
let nav = useNavigate();
let goBack = () => {
nav(-1); //주소 or 숫자
}
let goHome = () => {
nav('/'); //홈화면
}
return (
<>
<header className={style.wrap}>
<h3>헤더입니다</h3>
<ul className={style.wrap_list}>
<li>목록</li>
<li>목록</li>
<li>목록</li>
<li>목록</li>
</ul>
<div>
<button onClick={goHome}>홈으로</button>
<button onClick={goBack}>뒤로가기</button>
</div>
</header>
<section>
<Outlet/>
</section>
</>
)
}
export default Header;
'📍 프로그래밍 언어 > React' 카테고리의 다른 글
[ React / 한 입 크기로 잘라 먹는 리액트 ] 1장. 자바스크립트 기초 (5) | 2024.11.20 |
---|---|
[ React ] Ajax를 활용하여 외부 데이터 통신하기 (1) | 2024.11.09 |
[ React ] React에 CSS 적용하기 (0) | 2024.09.01 |
[ React ] 리액트 훅 (React Hook) (4) | 2024.08.31 |
[ React ] 컴포넌트 반복 (Map/Filter) (0) | 2024.08.31 |