๊ธฐ๋ฅ ๋ชฉ๋ก
- ๋ฉ์ธ ํ์ด์ง์์ ๋๋ฌผ ๋ชฉ๋ก ํ๋ฉด์ ํ์ํ๊ธฐ
- ๋๋ฌผ ์์ธ ์ ๋ณด ํ์ด์ง ๋ง๋ค๊ธฐ
- ๋๋ฌผ ์ด๋ฆ์ผ๋ก ๊ฒ์ ๊ธฐ๋ฅ & ๊ฒ์ ๊ฒฐ๊ณผ ํ์ด์ง ๋ง๋ค๊ธฐ
์ปดํฌ๋ํธ ๊ตฌ์ฑ
main.jsx
โฟ app.jsx
โฟ Main.jsx
โฟ Detail.jsx
โฟ Search.jsx
1. ๋๋ฌผ ๋ชฉ๋ก์ ํ๋ฉด์ ํ์ํ๊ธฐ
main.jsx
React Router๋ฅผ ์ฑ ์ ์ฒด์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด์ App ์ปดํฌ๋ํธ๋ฅผ BrowserRouter ์ปดํฌ๋ํธ๋ก ๊ฐ์ธ๊ณ ์๋ค.
createRoot(document.getElementById('root')).render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>,
);
App.jsx
๊ฐ๊ฐ์ Route์์๋ ๊ฐ ํ์ด์ง์ ์ปดํฌ๋ํธ๋ฅผ ์์๋ก ๋ถ๋ฌ์ ๋ถ๊ธฐ๋ณ๋ก ํ๋ฉด์ ํ์ํ๋๋ก ํ๊ณ ,
Routes๋ ์ด Route๋ค์ ๋ฌถ์ด์ฃผ๊ณ ์๋ค.
์ด๋ Detail ์ปดํฌ๋ํธ์์๋ ์์ธ ํ์ด์ง๋ก ์ด๋ํด์ผ ํ๋๋ฐ, ๊ฐ ํ์ด์ง์์ ํด๋น ์ ๋ณด๋ฅผ ๋ถ๋ฌ์ฌ ๊ณ ์ ํ id๊ฐ์ด ์์ด์ผ ํ๋ค.
์์ธ ํ์ด์ง์์ ๋ถ๋ฌ์ฌ ๋ฐ์ดํฐ๋ค์ ๋ชจ๋ ๊ณ ์ ํ id๊ฐ์ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ ๋ฐ์ดํฐ๋ค์ data.js ํ์ผ ๋ด์ ๋ด๊ฒจ์๋๋ฐ, data.js๋ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.
data.js์๋ ์๋์ ๊ฐ์ด ํค:๊ฐ์ ์๋ค๋ก ์ด๋ฃจ์ด์ง ๊ฐ์ฒด์ ๋ฐฐ์ด๋ก ์ด๋ฃจ์ด์ ธ ์๋ค. (์๋ ์ฝ๋๋ ๋ฐฐ์ด์ ์์ ์ค ํ๋์ด๋ค.)
์ด๋ images๋ images์ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ ์ํฌํธ๋ ํ์ผ์ ๋ณ์๋ค.
{
id:8,
name:'ํ๋ค',
img: images.panda,
description: 'ํ๋ค๋ ์ ์ ํ์ ์ผ๋ก ์ก์๋๋ฌผ์ ๊ฐ๊น๋ค.'
},
๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ(Path Parameter)๋ URL์ ๊ฒฝ๋ก ์ผ๋ถ๋ก ๊ฐ์ ์ ๋ฌํ๋ ๋ฐฉ์์ด๋ค.
์ด๋ฅผ ์ฌ์ฉํด URL์์ id ๊ฐ์ ๋ณ์์ฒ๋ผ ์ ๋ฌํ ์ ์์ผ๋ฉฐ, id์ ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ์์ธ ํ์ด์ง๋ฅผ ๋ง๋ค ์ ์๋ค.
function App() {
return (
<>
<header>
<h1>๐ ๋๋ฌผ ์กฐ์ ๐</h1>
</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>
</>
);
}
Main.jsx
data์ ๊ฐ ๊ฐ์ ๋ฆฌ์คํธ๋ก ๋ฐฐ์ดํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ map์ผ๋ก ๊ฐ๋ค์ ๊ฐ๊ฐ <li> ์์์ ๋ด์ ๋ฐํํด์ฃผ๊ณ ์๋ค.
function Main() {
return (
<ul>
{data.map((el) => (
<li key={el.id}>
<Link to={`/detail/${el.id}`}>
<img src={el.img}></img>
<div>{el.name}</div>
</Link>
</li>
))}
</ul>
);
}
data์ ๊ฐ ์์๊ฐ el์ด๋ผ๋ ๋งค๊ฐ๋ณ์์ ๋ค์ด์์ map ํจ์๋ก ๋ฐํ๋๊ณ ์๋ค.
key ์์ฑ์ el.id๊ฐ์ผ๋ก ๋ถ์ฌํ๊ณ , ํญ๋ชฉ์ ์ด๋ฏธ์ง์ ์ด๋ฆ๋ el.img, el.name์ผ๋ก ๋ฐ์์ค๊ณ ์๋ค.
ํด๋น liํ๊ทธ๋ฅผ ๋๋ฅด๋ฉด ๊ทธ ์์ธ ํ์ด์ง๋ก ์ด๋ํ๊ณ ์ถ๊ธฐ ๋๋ฌธ์ Link ์ปดํฌ๋ํธ๋ก ๊ฐ์ธ์ฃผ๊ณ ์๋๋ฐ,
Link์ to ์์ฑ์ /detail/:id'๋ก :id๋ฅผ ๊ฒฝ๋ก ๋ณ์๋ก ๋ฐ์์ ๊ณ ์ ํ id๊ฐ์ ๊ฐ์ง ํ์ด์ง๋ก ์ด๋ํ๊ฒ ํ๊ณ ์๋ค.
2. ๋๋ฌผ ์์ธ ์ ๋ณด ํ์ด์ง ๋ง๋ค๊ธฐ
Detail.jsx
Main.jsx์์ ๋๋ฌผ ์นด๋๋ฅผ ํด๋ฆญํ์ ๋, Link ์ปดํฌ๋ํธ๋ก ์ด๋ํ๋ฉด์ el.id๋ฅผ ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ๋ก ๋๊ธฐ๊ณ ์๋๋ฐ, ์ด๋ฅผ UseParams()์ ์ฌ์ฉํด ์ป์ด์ฌ ์ ์๋ค.
useParams()์ URL ๊ฒฝ๋ก์ ํฌํจ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ผ์ฐํฐ์ Hook ์ค ํ๋๋ก,
์์ App.jsx์์ Route ์ปดํฌ๋ํธ์์ ๋์ผํ ํ์()์ผ๋ก ์ง์ ํด๋จ๊ธฐ ๋๋ฌธ์, ๋ฌธ์ ์์ด ํ๋ผ๋ฏธํฐ ๊ฐ์ ๊ฐ์ ธ์ฌ ์ ์๋ค.
์๋ฅผ ๋ค์ด id๊ฐ 3๋ฒ์ธ ์นด๋๋ฅผ ํด๋ฆญํ์ ๋, const params = useParams();์ผ๋ก ๊ฒฝ๋ก์ ํ๋ผ๋ฏธํฐ๋ฅผ params๋ผ๋ ๋ณ์์ ๋ด๊ณ ์ด๋ฅผ ์ถ๋ ฅํ๋ฉด ์ด๋ ๊ฒ ์ถ๋ ฅ๋๋ค.
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>
);
}
ํ๋ผ๋ฏธํฐ๋ ๊ฐ์ ธ์๊ณ ์ด์ ์ด ์์ด๋์ ํด๋นํ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด์ find()๋ฅผ ์ฌ์ฉํด ํด๋น id๊ฐ๊ณผ ์ผ์นํ๋ ์ ๋ณด๋ฅผ ๋ณ์ animalData์ ์ ์ฅํ๋ค.
find() : ์ฒซ๋ฒ์งธ๋ก ์กฐ๊ฑด์ ๋ง๋ ๋จ์ผ ์์๋ฅผ ๋ฐํํ๋ค. (์์ ๊ฒฝ์ฐ undefined๋ฅผ ๋ฐํํ๋ค.)
์ด๋ useParams()์ ๋ชจ๋ ๊ฐ์ stringํ์ ์ผ๋ก ๋ฐํํ๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฅ el.id === params.id๋ฅผ ํ ๊ฒฝ์ฐ undefined๊ฐ ๋์จ๋ค. ๊ทธ๋์ Number()๋ก params.id๋ฅผ ์ซ์ ํ์ ์ผ๋ก ๋ณํํด ์ค์ ๋น๊ตํ๋ฉด ์ ์์ ์ผ๋ก id๊ฐ ์ผ์นํ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
3. ๋๋ฌผ ์ด๋ฆ์ผ๋ก ๊ฒ์๊ธฐ๋ฅ ๋ง๋ค๊ธฐ & ๊ฒ์ ๊ฒฐ๊ณผ ํ์ด์ง ์์ฑํ๊ธฐ
App.jsx
์ด๋ฒ ๊ฒฝ์ฐ์๋ ์์ ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ์๋ ๋ฌ๋ฆฌ ์ฟผ๋ฆฌ ์คํธ๋ง์ ์ ๋ณด๋ก ํ์ด์ง๋ฅผ ์ด๋ํด ํน์ ๋ฐ์ดํฐ๋ฅผ ์ป์ ์ ์๋ค.
์ฟผ๋ฆฌ ์คํธ๋ง์ URL์ ๋์ ?key=value ํํ๋ก ๋ถ๋ ์ถ๊ฐ ์ ๋ณด๋ก, ๋ฐ์ดํฐ๊ฐ ์ฌ๋ฌ ์์ผ ๊ฒฝ์ฐ &๋ก ์ฐ๊ฒฐํ๊ณ ์๋ค.
์ฃผ๋ก ๊ฒ์ ์กฐ๊ฑด, ํํฐ ๋ฑ์ ์ ๋ฌํ ๋ ์ฌ์ฉํ๋๋ฐ ์ด ๊ฒฝ์ฐ์๋ ๊ฒ์ ์กฐ๊ฑด์ ์ ๋ฌํ๊ณ ์๋ค.
function App() {
const [inputValue, setInputValue] = useState('');
const navigate = useNavigate();
return (
<>
<header>
<h1>๐ ๋๋ฌผ ์กฐ์ ๐</h1>
<input
value={inputValue}
onChange={(e) => setInputValue(e.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>
</>
);
}
๊ฒ์ ์กฐ๊ฑด์ ๊ฐ์ง URL๋ก ์ด๋ํ๊ธฐ ์ํด์ ๋จผ์ useNavigate()๋ก ํ์ด์ง ์ด๋์ ์ํ ํจ์ navigate๋ฅผ ์์ฑํ๋ค.
input์๋ ๊ฒ์์ด๋ฅผ ์ ๋ ฅ๋ฐ๊ณ , ์ ๋ ฅ๋ฐ์ ๊ฒ์์ด๋ ๋ฒํผ์ ๋๋ฅด๋ฉด navigate ํจ์๋ก ์์ ์ง์ ๋ ๊ฒฝ๋ก๋ก ์ด๋๋๋ค.
์ฟผ๋ฆฌ ์คํธ๋ง์ ๊ฒฝ์ฐ์๋ ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ์ ๋ฌ๋ฆฌ Route ์ปดํฌ๋ํธ์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ ํ ํ์๊ฐ ์๋ค.
๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ๋ ๋ง๊ทธ๋๋ก ๊ฒฝ๋ก ์์ ํฌํจ๋ ๋ณ์๊ณ , ์ด ์์ ์ ๋ณด๊ฐ ํฌํจ๋์ด ์์ด์ ๋ผ์ฐํฐ๊ฐ ์ง์ ํด์ํ๋ ๊ฑฐ๋ผ๋ฉด
์ฟผ๋ฆฌ ์คํธ๋ง์ ๊ฒฝ๋ก์ ์ฟผ๋ฆฌ ์คํธ๋ง์ด ๋ถ์ฌ์ง ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๋ผ์ฐํฐ๋ ์ฟผ๋ฆฌ ์คํธ๋ง์ ๋ฌด์ํ๊ณ Search ์ปดํฌ๋ํธ๋ง ๋ณด์ฌ์ค๋ค.
ํญ๋ชฉ | ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ | ์ฟผ๋ฆฌ ์คํธ๋ง |
๋ผ์ฐํฐ๊ฐ ํด์ | O | X (URL์ ์ผ๋ถ๋ก ๋ฌด์๋จ) |
์ฌ์ฉ ์ด์ | ๊ณ ์ ํ ๋ฐ์ดํฐ ์๋ณ | ์กฐ๊ฑด ์ ๋ฌ (๊ฒ์, ํํฐ, ์ ๋ ฌ ๋ฑ) |
ํ์ | /๊ฒฝ๋ก/ํ๋ผ๋ฏธํฐ๊ฐ | /๊ฒฝ๋ก?ํค=๊ฐ |
์ปดํฌ๋ํธ์์ ๋งค์นญ ์ฌ๋ถ | /๊ฒฝ๋ก/ํ๋ผ๋ฏธํฐ์ด๋ฆ ๊ณผ ์ผ์นํด์ผํจ | /๊ฒฝ๋ก ๋ง ์ผ์นํ๋ฉด ๋จ |
์ ๊ทผ ๋ฐฉ์ | useParams().ํ๋ผ๋ฏธํฐ์ด๋ฆ | useSearchParams().get('ํค') |
Search.jsx
๊ฒ์ํ ๋ ๋ฌธ์์ด์ ํจํด์ ํ์ธํ๊ธฐ ์ํด ์ ๊ท์์ ์ฌ์ฉํ๋ฉด ์ข์๋ฐ, ํ๊ธ๋ก ๊ฒ์ํ ๋ korean-regexp ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
korean-regexp๋ ํ๊ตญ์ด ์ ๊ท์์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค.
ํ๊ธ์ ๊ธฐ์ค์ผ๋ก ๋ง๋ ๊ฒ์ด๋ผ ์ด์ฑ/์ค์ฑ/์ข ์ฑ์ ๊ตฌ๋ถํ๊ธฐ ๋๋ฌธ์ ์ด์ฑ์ด๋ ๋ชจ์๋ง ์์ด๋ ๊ฒ์์ ํ ์ ์๋๋ก ๋์์ค ์ ์๋ค.
npm i korean-regexp
navigate()๋ก ๋์ด๊ฐ ์ฟผ๋ฆฌ ์คํธ๋ง์ ๊ฐ์ useSearchParams()๋ก ์ฝ์ด์๋ค.
์ด๋ useSearchParams()์ [๊ฐ์ฒด, ๊ฐ์ฒด ์ ๋ฐ์ดํธ ํจ์]๋ก ์์ฑํ ์ ์๋๋ฐ ์ด๋ฒ ์ค์ต์์๋ ๊ฒ์์ด๋ก ๊ฐ์ด ๋ณ๊ฒฝ๋๋ ๋ฐฉ์์ด๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด๋ง ๊ฐ์ ธ์์ ์์ฑํ๋ค.
์ฟผ๋ฆฌ ์คํธ๋ง์ ํค์ธ animal์ ๊ฐ(๊ฒ์์ด)์ param์ด๋ผ๋ ๋ณ์์ ๋ด์๊ณ , reg ๋ณ์๋ param์ ์ด์ฑ์๋ ๋งค์น๋ ์ ์๋๋ก ๋ง๋ค์ด์ง ์ ๊ท์ ๊ฐ์ฒด๋ฅผ ๋ด๊ณ ์๋ค.
๋ง์ง๋ง์ผ๋ก ํํฐ๋ง๋ ๋ฐ์ดํฐ๋ฅผ data์ filter ๋ฉ์๋๋ก ํํฐ๋งํด ์กฐ๊ฑด์ ๋ง๋ ๊ฐ๋ง ๊ฐ์ ธ์จ๋ค.
์ด ๋ match()๋ ๋ฌธ์์ด์ด ์ ๊ท์๊ณผ ์ผ์นํ๋ฉด, ์ผ์นํ๋ ๋ฌธ์์ด์ ํ๋งํ๋ array๋ฅผ ๋ฐํํ๋ ๋ฉ์๋๋ค.
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 filteredData = data.filter((el) => el.name.match(reg));
return (
<ul>
{filteredData.map((el) => (
<li key={el.id}>
<Link to={`/detail/${el.id}`}>
<img src={el.img}></img>
<div>{el.name}</div>
</Link>
</li>
))}
</ul>
);
}
export default Search;
+ ใ ใท๋ก ๊ฒ์ํ์ ๋ ํ๋ค๊ฐ ๋์ค์ง ์๋ ๊ฒฝ์ฐ
ใ ๋ก ๊ฒ์ํ๋ฉด ํ๋ค๋ ํญ๊ท์ด ์ ๋์ค๋๋ฐ, ์ด๋ 'ใ '์ด ๋จ์ด์ ์ด์ฑ์ผ๋ก ์์ ๋์ ๋ชจ๋ ๊ฒฝ์ฐ๋ฅผ ํฌํจํด์ฃผ๊ณ ์๊ธฐ ๋๋ฌธ์ ใ ๋ก ์์ํ๋ ๋จ์ด๋ ๋ค ํฌํจํด์ฃผ๊ณ ์๋ค.
๊ทธ๋ฐ๋ฐ ใ ใท๋ก ๊ฒ์ํ ๊ฒฝ์ฐ 'ใ ใท'๋ฅผ ์ด์ฑ์ ๋์ดํ ๋ฌธ์์ด๋ก ๊ฐ์ฃผํ ์๋ ์๊ธฐ ๋๋ฌธ์, ์ด์ฑ ๊ฒ์ ๊ธฐ๋ฅ ์ต์ ์ ์ถ๊ฐํด์ค์ผ๋๋ค.
๋ฐฉ๋ฒ์ ๊ฐ๋จํ๋ฐ, reg๋ฅผ ์ ์ธํ ๋ { initialSearch:true}๋ฅผ ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค
const reg = getRegExp(param, { initialSearch: true });
'react' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
React / useRef (0) | 2025.04.11 |
---|---|
React / ์๋ช ์ฃผ๊ธฐ (0) | 2025.04.10 |
React / Router (0) | 2025.04.09 |
React / ์กฐ๊ฑด๋ถ ๋ ๋๋ง (0) | 2025.04.09 |
React / state, props๋ฅผ ์ด์ฉํด CRUD ๊ธฐ๋ฅ์ ๊ฐ์ง Todo-List ๋ง๋ค๊ธฐ (0) | 2025.04.07 |