OZ

[Project] 동물조아

iun 2024. 12. 30. 04:12

아주 간단하고 심플한

동물 검색 사이트를 실습해봤다

 

참고로 이미지같은 데이터들은 자료제공으로 받아왔다

 

 

메인페이지에서 동물 목록 화면에 표시

// App.jsx
import "./App.css";
import { Routes, Route } from "react-router-dom";
import Main from "./page/Main";

function App() {
  return (
    <>
      <header>
        <h1>💚 동물 조아 💚</h1>
      </header>
      <Routes>
        <Route path="/" element={<Main />}></Route>
        <Route path="/detail" element={<Detail />}></Route>
        <Route path="/search" element={<Search />}></Route>
      </Routes>
      <footer>all rights reserved to OZ</footer>
    </>
  );
}

export default App;

 

웹사이트에 처음 접속하게 되면 구동되는 코드

정적으로 위치할 태그만 App.jsx에 추가해주고

동적으로 계속 변경될 태그들 Main, Detail, Search의 페이지를 각각 만들어 둔 후

React의 Router들로 특정 상호작용을 하면 각 페이지가 링크될 수 있게 연결해준다

// App.jsx
<Route path="/" element={<Main />}></Route>

 

여기서 처음으로 표시할 동적 페이지를 Main페이지로 링크해줬기 때문에

웹사이트에 처음 접속하면 App의 정적 태그랑 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} />
                    <div>{el.name}</div>
                </Link>
            </li>)}
        </ul>
    )
}

export default Main;

 

처음 표시될 동적 Main 페이지로

데이터파일을 불러와 그 안의 정보들을 전부 순회하면서

<Link>와 이미지, 이름 등을 추가해 화면에 표시한다

 

추가 기능 정리 (Router)

React는 SPA기반이기 때문에 여러 동적 페이지를 쉽게 관리할 수 있게 해주는 라이브러리이다

<Reates> 여러 Route를 감싸고 그 중의 하나를 렌더링 시켜주는 역할

<Route path=? element=?> path에는 경로를, element에는 컴포넌트를 연결

  • path="/"로 접근 시 메인페이지(첫화면)을 보여준다
  • path="/경로/상품번호"로 접근 시 상세페이지 형식으로 보여줄 수 있다

<Link to=?> 링크를 불러오는 역할. to에는 경로를 입력

  • 똑같은 기능인 <a>태그와의 차이는 리렌더링(새로고침)의 차이다
  • SPA의 큰 장점인 리렌더링없이 불러오는 것으로 Link로 그 기능을 사용할 수 있다

<BrouserRouter> 위의 기능들을 사용하기 위한 정의를 시켜주는 역할

// main.jsx
ReactDOM.createRoot(document.getElementById("root")).render(
  <BrowserRouter>
    <App /> // 최상위 컴포넌트 연결
  </BrowserRouter>
);

 

위처럼 최상위 컴포넌트 주변을 <BrowserRouter>로 감싸주면 된다

 

 

동물 상세 정보 페이지

// Detail.jsx
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;

 

// Main.jsx
<Link to={`/detail/${el.id}`}>
// App.jsx
<Route path="/detail/:id" element={<Detail />}></Route>

 

앞서 설정한 메인페이지에서 동물이미지를 클릭하면

<Link> 동적세그먼트로 상세페이지로 이동되게끔 했다

 

`/detail/${el.id}` 경로는 문자열로 구성하기 때문에 값도 불러오기 위해

템플릿 리터럴로 묶어서 경로 뒤 각 이미지의 식별자를 입력받게 한다

 

이후 해당 값이 무엇인지를 정의해야한다

그래서 App.jsx파일에서 Routepath속성에 "/detail/:id" 동적세그먼트: 기호를 추가해준다

 

이후 경로에서 값을 가져와야 하는데 Params를 사용해서 불러올 수 있다

 

const params = useParams();
const animalData = data.find((el) => el.id === Number(params.id))

 

data파일을 불러온 후 동작세그먼트로 지정한 id 값을 불러와 find로 순회해줬다

여기서 Number(params.id)로 불러온 이유는

경로 자체가 문자열로 구성되어있기도 하고

비교할 값의 타입이 숫자이기 때문에, 문자열을 숫자로 변환해주기 위함이다

 

 

 

동물 이름으로 검색기능 & 검색 결과 페이지 생성

// App.jsx
const [inputValue, setInputValue] = useState('')
  const navigate = useNavigate()
  return (
    <>
      <header>
        <input value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
        <button onClick={() => navigate(`/search?animal=${inputValue}`)}>검색</button>
        .
        .
        .

 

검색기능을 만들기 전 검색을 입력받고 출력할 공간이 필요하다

그래서 App파일에서 inputbutton을 만들어줬다

input에서 상태값을 받을 수 있게 useStatevalue상태를 만들어준다

그리고 button에서 클릭 시 input의 value상태로 주소이동할 수 있게 navigate함수를 사용한다

 

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

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

export default Search;

 

navigate으로 표시될 Search페이지다

경로에 있는 값을 가져오기위해 useSearchParams를 사용해 가져온다

해당 함수는 useState처럼 두가지 값을 배열로 반환하지만

주소를 input의 버튼으로 변경하기 때문에

useSearchParams를 사용할 일이 없어 값을 가져오지 않기로 한다

 

const reg = getRegExp(param)

 

좀 더 원활한 검색을 위해 korean-regexp 라이브러리를 사용한다

국내 사이트라면 웬만해선 적용되어있는 기능으로

원래는 완전한 글자를 만들어야 인식하지만
초성만 입력해도 해당 초성과 관련된 글자를 인식하게 해준다

예로 들면

 

목록(고양이/강아지/공룡/다람쥐)

[일반]

검색:강 강아지

검색:ㄱ 

[korean-regexp 적용]

검색:강 강아지

검색:ㄱ 고양이,강아지,공룡

 

위처럼 한국어 친화적으로 검색이 달라진다

 

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

 

korean-regexp 라이브러리 기능을 거치고

data를 filter로 순회하여 매치되는 정보들만 반환하게끔 한다

이후 화면에 표시하는 코드는 Main.jsx와 똑같이 한다

 

 

 

강의를 보면서 실습할 때엔 잘 됐는데

막상 혼자 해보면 오류투성이다...

익숙하지않아 단어도 기억나지않고

아무것도 기억이 안난다... ㅋㅋ

 

 

 

참고자료

'OZ' 카테고리의 다른 글

[React] 스타일링 SASS & SCSS  (1) 2025.01.03
[React] 컴포넌트 생명주기  (1) 2024.12.30
[React] SPA와 MPA  (2) 2024.12.21
25 일자 : 오랜만에 과제 일찍 끝냈다  (0) 2024.12.20
24 일차 : React 무썹다  (0) 2024.12.18