[ToyProject]검색창 구현

DU·2024년 11월 26일
0

Nobel-prize

목록 보기
3/3

검색창(SearchBox) 구현 코드 리뷰 🔍

이번 포스팅에서는 노벨상 탐색기 프로젝트의 핵심 기능 중 하나인 검색창과 관련된 코드를 리뷰합니다. 검색창은 사용자로부터 입력을 받아 API를 호출하고, 결과를 필터링하여 사용자에게 표시하는 중요한 UI/UX 요소입니다. 리뷰 대상은 다음과 같습니다:

  • SearchBox.js: 검색창 컴포넌트
  • SearchBox.css: 검색창 스타일링
  • SearchResults.js: 검색 결과를 표시하는 컴포넌트
  • SearchResults.css: 결과 목록 스타일링

1️⃣ SearchBox.js - 검색창 컴포넌트

import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import "./SearchBox.css";

function SearchBox({ onSearch }) {
  const [query, setQuery] = useState("");
  const [year, setYear] = useState("");
  const [prizeCategory, setPrizeCategory] = useState("");
  const navigate = useNavigate();

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      let apiUrl = `https://api.nobelprize.org/2.1/laureates?`;
      if (query) apiUrl += `name=${query}&`;
      if (year) apiUrl += `nobelPrizeYear=${year}&`;
      if (prizeCategory) apiUrl += `nobelPrizeCategory=${prizeCategory}`;

      const response = await fetch(apiUrl);
      const data = await response.json();

      const filteredData = data.laureates.filter((laureate) =>
        laureate.fullName.en.toLowerCase().startsWith(query.toLowerCase())
      );

      onSearch(filteredData || []);
      navigate("/search-results");
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };

  return (
    <div className="search-container">
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="이름 검색"
        />
        <input
          type="text"
          value={year}
          onChange={(e) => setYear(e.target.value)}
          placeholder="수상 연도"
        />
        <input
          type="text"
          value={prizeCategory}
          onChange={(e) => setPrizeCategory(e.target.value)}
          placeholder="수상 종류"
        />
        <button type="submit">검색</button>
      </form>
    </div>
  );
}

export default SearchBox;

📌 리뷰 포인트

  1. 구조적 완성도

    • useState를 활용해 검색 필드의 상태를 관리하며, 입력값에 실시간으로 반응합니다.
    • useNavigate를 사용해 검색 결과 페이지로 이동을 구현한 점이 효율적입니다.
  2. API 호출 및 데이터 처리

    • 조건에 따라 API URL을 동적으로 생성하며, 사용자 입력값에 맞는 데이터를 필터링하는 로직이 명확합니다.
    • try-catch 블록을 사용해 에러를 처리하고 있어 안정성이 돋보입니다.
  3. 코드 개선 제안

    • Validation 추가: 연도나 상 종류가 유효하지 않은 경우 적절한 경고 메시지를 표시하는 로직을 추가하면 사용자 경험이 개선됩니다.
    • 필드 초기화: 검색이 완료된 후 입력값을 초기화하는 기능을 고려해보세요.
      setQuery("");
      setYear("");
      setPrizeCategory("");

2️⃣ SearchBox.css - 검색창 스타일링

.search-container {
  width: 100%;
  max-width: 800px;
  margin: 50px auto;
  padding: 20px;
  background-color: #f9f9f9;
  border-radius: 8px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

form {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
}

input {
  width: 30%;
  padding: 12px;
  border: 1px solid #ccc;
  border-radius: 5px;
  font-size: 1rem;
  box-sizing: border-box;
}

input:focus {
  border-color: #007bff;
  outline: none;
  box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
}

button {
  width: 20%;
  padding: 12px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 5px;
  font-size: 1.1rem;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

button:hover {
  background-color: #0056b3;
}

📌 리뷰 포인트

  1. 레이아웃 및 스타일링

    • flexbox를 사용하여 각 필드를 깔끔하게 정렬하고 간격을 유지하였습니다.
    • box-shadowborder-radius로 검색창에 부드러운 느낌을 더했습니다.
  2. 디자인 개선 제안

    • 반응형 디자인: 모바일 화면에서 입력 필드와 버튼이 너무 좁아 보일 수 있으므로, 미디어 쿼리를 통해 필드의 너비를 100%로 조정하는 것이 좋습니다.
      @media (max-width: 768px) {
        input, button {
          width: 100%;
          margin-bottom: 10px;
        }
      }

3️⃣ SearchResults.js - 검색 결과 표시

import React from "react";
import "./SearchResults.css";

function SearchResults({ searchResults }) {
  if (!searchResults || searchResults.length === 0) {
    return <div>검색 결과가 없습니다.</div>;
  }

  return (
    <div className="search-results">
      <h2>검색 결과</h2>
      <ul>
        {searchResults.map((result, index) => (
          <li key={index}>
            <h3>{result.knownName?.en || result.fullName?.en || "이름 없음"}</h3>
            <p>수상 연도: {result.nobelPrizes[0]?.awardYear}</p>
            <p>수상 종류: {result.nobelPrizes[0]?.category?.en}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default SearchResults;

📌 리뷰 포인트

  1. 구조적 간결성

    • 조건부 렌더링을 통해 결과가 없을 경우 메시지를 출력하는 구조가 명확합니다.
    • API 응답 데이터를 적절히 매핑하여 사용자에게 필요한 정보를 제공합니다.
  2. 코드 개선 제안

    • 로딩 상태 추가: API 호출 중 로딩 스피너를 표시하면 사용자 경험이 향상됩니다.
      const [isLoading, setIsLoading] = useState(false);

4️⃣ SearchResults.css - 결과 스타일링

.search-results {
  margin: 20px;
  padding: 20px;
  background-color: #f9f9f9;
  border: 1px solid #ddd;
  border-radius: 8px;
}

.search-results h2 {
  font-size: 24px;
  margin-bottom: 16px;
}

.search-results li {
  padding: 15px;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 6px;
  margin-bottom: 16px;
}

📌 리뷰 포인트

  • 결과 목록을 깔끔하게 정리한 스타일링이 돋보입니다.
  • 호버 효과로 시각적 피드백을 제공하는 점이 유용합니다.

마무리 ✨

이 코드는 검색창 구현과 관련된 구조적 완성도와 디자인의 균형이 돋보입니다. 다만, 추가적인 UX 개선 사항(로딩 상태, 에러 처리 등)을 반영하면 더 나은 사용자 경험을 제공할 수 있습니다.

0개의 댓글