개발/React&Redux

[React] React Router를 활용한 동물 소개 페이지 만들기

xuwon 2024. 10. 16. 18:09

부트캠프에서 React를 배우면서, 간단한 동물 소개 페이지를 만드는 법을 배웠습니다.

구현한 기능은

1. 메인 페이지에서 동물 목록 화면에 표시하기
2. 동물 상세 정보 페이지 만들기
3. 동물 이름으로 검색할 수 있는 기능 만들기
4. 검색 결과 페이지 만들기

이렇게입니다.

<!-- App.jsx -->

import { useState } from "react";
import "./App.css";
import { Route, Routes, useNavigate } from "react-router-dom";
import Detail from "./page/Detail";
import Search from "./page/Search";
import Main from "./page/Main";

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="/main" element={<Main />}></Route>
        <Route path="/detail/:id" element={<Detail />}></Route> 
        {/* /:id를 붙임으로써 id를 받아서 detail 페이지로 넘어가게끔 */}
        <Route path="/search" element={<Search/>}></Route>
      </Routes>

      <footer>all rights reserved to OZ</footer>
    </>
  );
}

export default App;

App.jsx 파일입니다.

React Router를 사용해야 하기 때문에, App 컴포넌트를 <BrowserRouter>로 묶어주었습니다.
그리고 <Routes><Route>를 통해 특정 주소에서 어떤 컴포넌트를 보여줘야 하는지를 작성하였습니다.

/main 경로에서는 Main 컴포넌트를,
/detail 경로에서는 Detail 컴포넌트를,
/search 경로에서는 Search 컴포넌트를 보여주도록 작성했습니다.


/detail 경로의 경우, 각 동물들의 소개를 보여주는 상세 페이지이므로,
동물들의 id를 받아 각 detail 페이지로 이동하게끔 path"/detail/:id"로 작성하였습니다.

 

 

Main 컴포넌트

 

<!-- Main.jsx -->

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}></img>
                    <div>{el.name}</div>
                </Link>
            </li>)}
        </ul>
    )
}

export default Main;

Main 컴포넌트는 동물들의 목록을 보여줍니다.


  import { data } from "../assets/data/data";  
으로 assets 폴더 안의 data 폴더 안에 위치한 data.js 파일을 불러왔습니다.

data.js는 각 동물들의 정보가 객체 형태로 작성되어 배열 안에 들어있는 구조입니다.


data.map() 함수는 data 배열의 각 요소를 순회하며, el각 동물의 데이터를 전달합니다.
각 데이터로 이미지와 이름을 가진 <li> 항목을 생성하고, 고유한 key 값으로 el.id를 사용합니다.

이미지와 이름을 <Link>로 묶어, 해당 태그를 클릭했을 때

`/detail/${el.id}`
이 주소로 이동하게끔 작성하였습니다.

<Link>는 React Router에서 사용하는 컴포넌트로, 클릭 시 새로고침 없이 해당 경로로 이동하게 해줍니다.
여기서는 각 동물의 id를 URL에 포함시켜, /detail/${el.id} 경로로 이동할 수 있도록 했습니다.


아까 App.jsx에서 언급했는데
/detail 경로에서 id를 받아서 각 동물들의 detail 페이지로 이동한다고 했습니다.
따라서 Main 컴포넌트에서 dataid를 함께 전달하여 해당 페이지로 이동할 수 있도록 만들어주면 됩니다.



즉, Main 컴포넌트는 동물의 데이터 목록을 불러와 각 항목을 <Link>로 감싼 이미지와 이름으로 표시하며,
링크를 클릭하면 해당 동물의 상세 페이지로 이동하도록 작성되었습니다.

 


결과는 이렇게 됩니다!

 

 

Detail 컴포넌트

<!-- Detail.jsx -->

import { useParams } from "react-router-dom";
import { data } from "../assets/data/data";

function Detail() {
    const params = useParams();
    console.log(params.id); 

    const animalData = data.find(el => el.id === Number(params.id));
    // params에서 받아온 값은 문자열
    console.log(animalData);

    return (
        <section className="detail">
            <img src={animalData.img} />
            <h2>{animalData.name}</h2>
            <div>{animalData.description}</div>
        </section>
    )
}

export default Detail;

각 동물들의 상세 페이지를 나타내는 컴포넌트입니다.

먼저, useParams()를 통해 URL에서 id 값을 추출합니다.

useParams()는 React Router에서 제공하는 훅(hook)으로, 현재 URL의 매개변수 값을 객체 형태로 반환합니다.
여기서는 URL에서 id 값을 추출하여 각 동물의 데이터를 가져오는 데 사용됩니다.



그리고 여기서도 Main 컴포넌트와 똑같이 assets 폴더에 있는 data.js 파일을 불러옵니다.
그 다음으로는 data.find()를 사용해 해당 id와 일치하는 동물의 데이터를 찾습니다.

data.find()는 배열에서 조건에 맞는 첫 번째 요소를 찾아 반환하는 메서드입니다.
(idkey값이니, 고유한 값입니다.)

URL에서 추출한 params.id는 문자열로 제공되기 때문에, 비교를 위해 Number()로 숫자로 변환해 줍니다.
이를 통해 animalData에는 해당 id를 가진 동물의 데이터가 객체로 저장됩니다.

 

이 정보를 리턴해주면 상세 정보 페이지 표시도 끝! 

결과는...

귀여운 소개 페이지 완성~


 

 

Search 컴포넌트

 

<!-- Search.jsx -->

import { useSearchParams, Link } from "react-router-dom";
import { data } from "../assets/data/data";
import { getRegExp } from "korean-regexp";

function Search() {
    const [seachParams] = useSearchParams();
    const param = seachParams.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;

Search 컴포넌트는 검색한 내용을 바탕으로 해당되는 동물들의 목록을 나타냅니다.


useSearchParams()는 React Router에서 제공하는 훅으로, URL의 쿼리 문자열을 가져오고 이를 파싱해 사용할 수 있도록 도와줍니다.
여기서는 URL에 포함된 ?animal=검색어의 값인 animal을 추출하여 param 변수에 할당합니다.


App 컴포넌트에서

<header>
    <h1>💚 동물 조아 💚</h1>
    <input value={inputValue} onChange={(event) => setInputValue(event.target.value)}/>
    <button onClick={() => navigate(`/search?animal=${inputValue}`)}>검색</button>
</header>

button이 클릭되었을 때 navigate()를 통해
`/search?animal=${inputValue}`로 이동하도록 작성해 주었는데요.

1. 검색 버튼이 클릭되면 /search?animal=${inputValue} 형식의 URL로 이동합니다.
2. 이 URL에는 사용자가 입력한 검색어가 쿼리 스트링으로 포함됩니다.
3. useSearchParams()를 사용해 쿼리 스트링에서 animal 값을 추출해 param 변수에 저장하고, 이를 바탕으로 필터링 작업을 수행합니다.

이런 과정으로 진행됩니다.



이제 받아온 검색어와 동물 데이터의 이름을 비교해야 합니다.

getRegExp() 함수를 사용하여 검색어를 정규식으로 변환한 후,
이 정규식을 filter() 메소드와 match()를 사용해 동물의 이름과 비교합니다.

  const filteredData = data.filter((el) => el.name.match(reg));  


korean-regexp
라이브러리는 한국어에 특화되어 있어
한국어의 자음, 모음, 초성 등과 같은 특성을 고려하여 정규식을 처리해 주는 기능을 제공합니다.

이름이 정규식과 일치하는 항목만 filteredData에 저장되고, 이를 통해 필터링된 결과를 화면에 표시할 수 있습니다.

필터링된 데이터를 Main 컴포넌트에서와 마찬가지로 페이지에 출력해주면 끝입니다.

ㅍ을 검색한 경우, 판다와 펭귄이 출력되는 것을 볼 수 있습니다.

 

 

이렇게 동물 소개 페 이지의 설명을 마치겠습니다 . . .