현재 오즈코딩스쿨 강의를 통해 프론트엔드를 학습하고 있습니다.
본 포스트는 해당 강의에 대한 내용 정리를 목적으로 합니다.
React에서는 조건에 따라 특정 컴포넌트를 화면에 보이게 하거나 숨기는 것을 조건부 렌더링이라 부른다.
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <h1>다시 오신 것을 환영하오이다</h1>;
}
return <h1>회원가입 해주시기 바라오이다</h1>;
}
가장 기본적인 조건 분기 방식이다.
function Notification(props) {
const hasNewMessage = props.hasNewMessage;
return (
<div>
<h1>마이 페이지이다</h1>
{hasNewMessage && <p>새로운 메시지가 있소이다</p>}
</div>
);
}
조건이 참일 때만 뒤의 JSX가 렌더링된다.
function UserStatus(props) {
return (
<div>
{props.isOnline ? <p>접속 중이다</p> : <p>접속 종료 상태이다</p>}
</div>
);
}
조건에 따라 두 가지 경우 중 하나를 선택하여 출력할 수 있다.
function WarningBanner(props) {
if (!props.warn) {
return null; // 아무것도 렌더링하지 않는다
}
return <div className="warning">경고 메시지이다</div>;
}
null을 반환하면 아무것도 그려지지 않는다.
React Router는 React에서 페이지 전환을 구현할 수 있게 도와주는 라이브러리이다.
Single Page Application(SPA) 구조에서도 주소(URL)를 바꾸면 다른 컴포넌트를 보여줄 수 있도록 한다.
npm install react-router-dom
npm i react-router-dom
React Router를 사용하고 싶은 곳을 <BrowserRouter> 컴포넌트로 감싼다.
<App /> 컴포넌트를 감싸버리면 어디서든 사용 가능하다.
import { BrowserRouter } from 'react-router-dom';
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
이것은 앱 내에서 라우팅을 사용할 수 있도록 만들어주는 최상위 설정이다.
<Link> 컴포넌트와 to속성을 사용해서 이동하고 싶은 주소로 이동할 수 있다.
이때 <Link>컴퍼넌트는 <a>요소로 표시되지만 새로고침은 발생하지 않고 주소만 변경된다!
import { Link } from 'react-router-dom';
function NavBar() {
return (
<nav>
<Link to="/main">메인</Link>
<Link to="/mypage">마이페이지</Link>
<Link to="/test">테스트</Link>
</nav>
);
}
<Routes>컴포넌트는 <Route>컴포넌트들을 묶어주는 역할<Route>컴포넌트는 특정 주소에서 어떤 컴포넌트를 보여줄지 정해주는 역할import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
function App() {
return (
<Routes>
<Route path="/main" element={<Main />} />
<Route path="/mypage" element={<MyPage />} />
<Route path="/test" element={<Test />} />
</Routes>
);
}
Route는 URL 경로와 그에 해당하는 컴포넌트를 연결해주는 역할을 한다.
특정 주소로 이동할 수 있게 해주는 함수를 생성
import { useNavigate } from 'react-router-dom';
function MyComponent() {
const navigate = useNavigate();
const goToAbout = () => {
navigate('/about');
};
return (
<button onClick={goToAbout}>
소개 페이지로 이동
</button>
);
}
navigate('/경로') 형태로 원하는 경로로 이동할 수 있다.
현재 페이지의 위치 정보를 담고있는 객체를 생성
import { useLocation } from 'react-router-dom';
const location = useLocation();
{
pathname: "/about", // 현재 경로
search: "?mode=dark", // 쿼리 스트링
hash: "#section1", // 해시값
state: { from: "/login" }, // navigate 시 넘긴 state
key: "abc123" // 고유 키값
}
navigate로 넘긴 데이터를 useLocation으로 받을 수 있다.주소의 쿼리 파라미터 값을 담은 객체 생성
import { Routes, Route } from 'react-router-dom';
import UserPage from './pages/UserPage';
function App() {
return (
<Routes>
<Route path="/user/:id" element={<UserPage />} />
</Routes>
);
}
useParams()는 URL에서 설정한 :id 값을 객체 형태로 반환한다.
주소의 쿼리 스트링 값을 가져올 수 있는 객체와 쿼리 스트링을 수정할 수 있는 함수 생성
import { useSearchParams } from 'react-router-dom';
function ProductList() {
const [searchParams, setSearchParams] = useSearchParams();
const category = searchParams.get('category');
const page = searchParams.get('page');
return (
<div>
<h1>카테고리: {category}이다</h1>
<p>{page} 페이지이다</p>
</div>
);
}
searchParams.get('key') 형태로 값을 가져올 수 있다.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { BrowserRouter } from "react-router-dom";
ReactDOM.createRoot(document.getElementById("root")).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
<Routes>
<Route path='/' element={<Main /> }></Route>
<Route path='/detail/:id' element={<Detail />}></Route>
<Route path='/search' element={<Search />}></Route>
</Routes>
<Link to={`/detail/${el.id}`}>
<img src={el.img} />
<div>{el.name}</div>
</Link>
먼저 동물 데이터를 따로 저장할 data.js 파일을 만든다.
아래와 같이 객체 배열 형태로 정의하면 된다.
import images from "./images"
export const data = [
{
id:0,
name:'고양이',
img: images.cat,
description: '나만 고양이 없어..'
},
{
id:1,
name:'소',
img: images.cow,
description: '어린 송아지가 부뚜막에 앉아 울고 있어요'
},
{
id:2,
name:'강아지',
img: images.dog,
description: '강아지 귀여워'
},
{
id:3,
name:'오리',
img: images.duck,
description: '오리는 뒤집어지면 혼자 일어나지 못한다'
},
{
id:4,
name:'여우',
img: images.fox,
description: 'What Does the Fox Say?'
},
{
id:5,
name:'개구리',
img: images.frog,
description: '콩쥐야... 망했어...'
},
{
id:6,
name:'기린',
img: images.giraffe,
description: '기린은 하루에 10분에서 2시간만 잔다.'
},
{
id:7,
name:'사자',
img: images.lion,
description: '카카오의 라이언은 탈모 사자다.'
},
{
id:8,
name:'판다',
img: images.panda,
description: '판다는 유전학적으로 육식동물에 가깝다.'
},
{
id:9,
name:'펭귄',
img: images.penguin,
description: '펭귄은 사실 롱다리다.'
},
{
id:10,
name:'돼지',
img: images.pig,
description: '돼지는 배가 부르면 그 이상 먹지 않습니다.'
},
{
id:11,
name:'토끼',
img: images.rabbit,
description: '암컷 토끼는 싸울 때 수컷의 얼굴을 초당 5회까지 때릴 수 있습니다.'
},
{
id:12,
name:'양',
img: images.sheep,
description: '잠이 안올 때 양을 세는 이유는 sleep과 sheep의 발음이 비슷해서다.'
},
{
id:13,
name:'호랑이',
img: images.tiger,
description: '호랑이 털의 무늬는 지문 같은 역할을 한다.'
},
]
id, name, img, description 속성으로 구성된 객체 배열이다.images는 cat, dog, fox 등 각각의 이미지를 key로 가지는 객체이며, 이로써 각 동물의 이미지를 코드에서 바로 참조할 수 있다.export 되었기 때문에 다른 컴포넌트에서 import 하여 사용할 수 있다.import { Link } from "react-router-dom";
import { data } from "../assets/data/data"
function Main() {
return (
<ul>
{data.map(el => (
<li key={el.id}>
<Link to={`/detail/${el.id}`}>
<img src={el.img} />
<div>{el.name}</div>
</Link>
</li>
))}
</ul>
);
}
export default Main;
data를 map()으로 순회하면서 각 동물 항목을 리스트로 렌더링하는 구조이다.li로 감싸져 있으며, 내부에 Link 컴포넌트를 사용하여 상세 페이지로 이동할 수 있도록 되어 있다.Link의 to 속성은 /detail/{id} 경로로 이동하도록 설정되어 있다.img 태그의 src는 el.img, alt는 el.name으로 설정하여 이미지 접근성과 명확성을 높이고 있다.import { Link } from "react-router-dom";
import { data } from "../assets/data/data"
function Main() {
return (
<ul>
{data.map(el => (
<li key={el.id}>
<Link to={`/detail/${el.id}`}>
<img src={el.img} />
<div>{el.name}</div>
</Link>
</li>
))}
</ul>
);
}
export default Main;
react-router-dom의 Link 컴포넌트를 사용하여 경로 이동을 처리하는 방식이다.
el.id는 각 동물 객체의 고유한 id 값이며, 이를 포함한 주소(/detail/1, /detail/5 등)로 연결되는 것이다.
import { useState } from "react";
import "./App.css";
import { Route, Routes, useNavigate } from "react-router-dom";
import Main from "./page/Main";
import Detail from "./page/Detail";
import Search from "./page/Search";
function App() {
const [inputValue, setInputValue] = useState('')
const navigate = useNavigate()
return (
<>
<header>
<h1>💚 동물 조아 💚</h1>
<input value={inputValue} onChange={(event) =>
setInputValue(event.target.value)} />
<button onClick={() => navigate(`/search?animal=${inputValue}`)}>
검색
</button>
</header>
<Routes>
<Route path='/' element={<Main /> }></Route>
<Route path='/detail/:id' element={<Detail />}></Route>
<Route path='/search' element={<Search />}></Route>
</Routes>
<footer>all rights reserved to OZ</footer>
</>
);
}
export default App;
<Route path="/detail/:id">는 동적 라우팅이다.:id는 경로의 일부분이며, 사용자가 실제로 클릭한 동물의 id 값으로 대체되는 것이다.import { useParams } from "react-router-dom";
import { data } from "../assets/data/data";
function Detail() {
const params = useParams();
const animalData = data.find((el) => el.id === Number(params.id));
return (
<section className="detail">
<img src={animalData.img} />
<h2>{animalData.name}</h2>
<div>{animalData.description}</div>
</section>
);
}
export default Detail
useParams() 훅은 경로에서 :id 부분의 값을 추출하는 역할을 한다.params.id는 문자열(string)이므로, 비교를 위해 Number()를 사용해 숫자로 변환하는 것이 일반적이다.data.find()를 통해 해당 id를 가진 동물 객체를 찾아 화면에 표시하는 구조이다.import { useParams } from "react-router-dom";
import { data } from "../assets/data/data";
function Detail() {
const params = useParams(); // URL 경로에 포함된 id 값을 가져온다. 예: { id: "3" }
// data 배열에서 id 값이 일치하는 동물 데이터를 찾아낸다
const animalData = data.find((el) => el.id === Number(params.id));
return (
<section className="detail">
<img src={animalData.img} alt={animalData.name} />
<h2>{animalData.name}</h2>
<div>{animalData.description}</div>
</section>
);
}
export default Detail;
/detail/:id는 동적 경로를 의미하며, 사용자가 /detail/5 같은 경로로 이동할 때, useParams()를 통해 해당 id 값이 컴포넌트로 전달되는 것이다.import { Link, useSearchParams } from "react-router-dom";
import { data } from "../assets/data/data";
import { getRegExp } from "korean-regexp";
function Search() {
const [searchParams] = useSearchParams();
const param = searchParams.get('animal');
const reg = getRegExp(param);
const filterdData = data.filter(el => el.name.match(reg));
return (
<ul>
{filterdData.map(el => (
<li key={el.id}>
<Link to={`/detail/${el.id}`}>
<img src={el.img} />
<div>{el.name}</div>
</Link>
</li>
))}
</ul>
);
}
export default Search;
useSearchParams()는 ?animal=고양이처럼 URL 쿼리스트링에 포함된 데이터를 읽어올 수 있게 해주는 훅이다.searchParams.get("animal")로 해당 키의 값을 추출하는 방식이다.import { useNavigate } from "react-router-dom";
function App() {
const [inputValue, setInputValue] = useState('');
const navigate = useNavigate();
const handleSearch = () => {
navigate(`/search?animal=${inputValue}`);
};
return (
<>
<input value={inputValue} onChange={(event) => setInputValue(e.target.value)} />
<button onClick={handleSearch}>검색</button>
</>
);
}
useNavigate()는 프로그래밍적으로 페이지 경로를 변경할 수 있게 해주는 훅이다.navigate()를 사용하여 검색어를 쿼리로 포함한 경로로 이동시키는 것이다.navigate("/search?animal=강아지")처럼 쓰면, Search.jsx 페이지가 렌더링되며 해당 데이터를 읽게 된다.korean-regexp는 한글 초성 검색이 가능하도록 도와주는 유틸리티 라이브러리이다.
https://www.npmjs.com/package/korean-regexp/v/1.0.7
npm i korean-regexp
import { useSearchParams } from "react-router-dom";
import { data } from "../assets/data/data";
import { getRegExp } from "korean-regexp";
useSearchParams: URL에서 쿼리 문자열을 추출하기 위해 사용한다.data: 전체 동물 데이터 목록이다.getRegExp: 검색어를 정규표현식으로 변환해주는 함수로, 초성 검색을 가능하게 한다.const [searchParams] = useSearchParams();
const param = searchParams.get('animal');
/search?animal=고양이처럼 입력되었을 때 "고양이"가 param으로 저장된다.
const reg = getRegExp(param);
getRegExp("ㄱㅇ") → /.*ㄱ.*ㅇ.*/ 와 같은 정규식이 만들어진다.const filteredData = data.filter(el => el.name.match(reg));
match(reg)를 통해 부분 일치 여부를 판단한다.filteredData 배열에 담긴다.
머리가 멍~
라우트 어려워요..ㅠㅠ