React/Animal Crossing Project

동물의 숲 웹페이지 만들기 - 동숲 주민 종류 필터링(4)

효니님 2024. 9. 5. 18:44
728x90

 

<select> 박스를 이용해 동물의 숲 주민 목록을 동물 종류에 따라 필터링해

특정 동물 종류를 선택해서 해당하는 주민들만 볼 수 있도록 구현해 봤다.

 

우선 이전에 생성해 두었던 translations.js에 중복되거나 필요 없는 객체가 있어 수정했다.

const speciesKr = {
  "Alligator": "악어",
  "Anteater": "개미핥기",
  "Bear": "곰",
  "Bear cub": "아기곰",
  "Bird": "새",
  "Bull": "황소",
  "Cat": "고양이",
  "Chicken": "닭",
  "Cow": "소",
  "Deer": "사슴",
  "Dog": "개",
  "Duck": "오리",
  "Eagle": "독수리",
  "Elephant": "코끼리",
  "Frog": "개구리",
  "Goat": "염소",
  "Gorilla": "고릴라",
  "Hamster": "햄스터",
  "Hippo": "하마",
  "Horse": "말",
  "Koala": "코알라",
  "Kangaroo": "캥거루",
  "Lion": "사자",
  "Monkey": "원숭이",
  "Mouse": "쥐",
  "Octopus": "문어",
  "Ostrich": "타조",
  "Penguin": "펭귄",
  "Pig": "돼지",
  "Rabbit": "토끼",
  "Rhino": "코뿔소",
  "Sheep": "양",
  "Squirrel": "다람쥐",
  "Tiger": "호랑이",
  "Wolf": "늑대",
}

종류가 정말 많다..ㅎㅎ

 


 

const [selectedSpecies, setSelectedSpecies] = useState('');

// 선택된 동물 종류에 따른 필터링
const filteredVillagers = selectedSpecies
  ? data.filter(villager => villager.species === selectedSpecies)
  : data;

// 동물 종류를 클릭했을 때 호출되는 함수
const handleSpeciesClick = (species) => {
  setSelectedSpecies(species);
};
  
return (
  <div className='container'>
    <h1>동물의 숲</h1>
    <div className="species-selector">
      <select
        value={selectedSpecies}
        onChange={(e) => handleSpeciesClick(e.target.value)}>
        {Object.values(speciesKr).map((species, idx) => (
          <option key={idx} value={species}>
            {species}
          </option>
        ))}
        <option value="">전체 보기</option>
      </select>
    </div>
    <VillagerList villagers={filteredVillagers} />
  </div>
);

상태 관리와 연동해서 선택된 옵션에 따라 필터링 기능을 적용할 수 있도록 했다.

 

<select
  value={selectedSpecies}
  onChange={(e) => handleSpeciesClick(e.target.value)}>
  {Object.values(speciesKr).map((species, idx) => (
    <option key={idx} value={species}>
      {species}
    </option>
  ))}
  <option value="">전체 보기</option>
</select>

select의 value속성은 selectedSpecies(현재 선택된 값)로 설정했다.

selectedSpecies는 선택된 동물 종류를 나타낸다.

만약 '고양이'를 선택하면 해당 값은 selectedSpecies에 저장된다.

 

셀렉트 박스에서 옵션을 선택하면 onChange 이벤트가 발생하고,

e.target.value(선택한 동물 종류의 값)을 handleSpeciesClick함수로 전달해 selectedSpecies상태가 변경되도록 했다.

 

{Object.values(speciesKr).map((species, idx) => (
  <option key={idx} value={species}>
    {species}
  </option>
))}

Object.values() 함수를 사용해 speciesKr객체의 값만 배열로 반환하고, 

map() 함수를 통해 값을 반복하면서 각 동물 종류마다 option태그를 생성해 value값을 추가했다.

 

전체 보기 옵션은 value값을 비워 모든 주민이 보이도록 했다.

 

필터링 기능

const filteredVillagers = selectedSpecies
  ? data.filter(villager => villager.species === selectedSpecies)
  : data;

selectedSpecies에 값이 있으면 해당 동물 종류로 필터링된 주민 데이터를 반환하고,

값이 없으면 모든 주민 데이터를 반환하도록 했다.

 

동물 종류 선택 처리

const handleSpeciesClick = (species) => {
  setSelectedSpecies(species); // 선택된 동물 종류 상태 업데이트
};

handleSpeciesClick함수는 선택된 값을 받아 상태를 업데이트하고,

selectedSpecies가 변경되면 화면에 보여줄 주민 목록이 필터링된다.

 

 

<VillagerList villagers={filteredVillagers} />

필터링된 주민 목록을 출력하면!!

 

 

 

선택한 종류별로 화면에 잘 보인다 :)

 

전체 코드

// Home.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import VillagerList from '../component/VillagerList';
import { villagers } from 'animal-crossing';
import { genderKr, personalityKr, speciesKr } from '../translations/translations';


function Home() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [selectedSpecies, setSelectedSpecies] = useState('');

  const fetchData = async () => {
    const URL = "https://api.nookipedia.com/villagers?game=nh&game=pc";

    try {
      setLoading(true);
      const response = await axios.get(URL, {
        headers: {
          "X-API-KEY": process.env.REACT_APP_API_KEY,
          "Accept-Version": "1.0.0",
        },
      });
      const animal = response.data.map(currentVillager => {
        const matchingVillager = villagers.find(villager => villager.name === currentVillager.name);
        if (matchingVillager) {
          return {
            ...currentVillager,
            name: matchingVillager.translations.kRko,
            species: speciesKr[matchingVillager.species],
            personality: personalityKr[matchingVillager.personality],
            gender: genderKr[matchingVillager.gender],
          }
        }
        return null;
      });
      setData(animal);
    } catch (error) {
      setError(error.message);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchData();
  }, []);

  // 선택된 동물 종류에 따른 필터링
  const filteredVillagers = selectedSpecies
    ? data.filter(villager => villager.species === selectedSpecies)
    : data;

  // 동물 종류를 클릭했을 때 호출되는 함수
  const handleSpeciesClick = (species) => {
    setSelectedSpecies(species);
  };

  if (loading) return <p>Loading...</p>;
  if (error) return <p>에러: {error}</p>;

  return (
    <div className='container'>
      <h1>동물의 숲</h1>
      <div className="species-selector">
        <select
          value={selectedSpecies}
          onChange={(e) => handleSpeciesClick(e.target.value)}>
          {Object.values(speciesKr).map((species, idx) => (
            <option key={idx} value={species}>
              {species}
            </option>
          ))}
          <option value="">전체 보기</option>
        </select>
      </div>
      <VillagerList villagers={filteredVillagers} />
    </div>
  );
}

export default Home;

 

css도 수정해야 하지만 우선 원하던 기능은 되는 것 같아서 뿌듯..ㅎ

 

728x90