[Personal Project] 나라 API로 받아온 나라 목록 리스팅 (2)

liinyeye·2024년 7월 1일
0

Project

목록 보기
24/44

튜터 피드백

피드백 반영

최적화

useCallback 사용

  • 불필요한 재렌더링 방지: onToggleSelect와 sortCountries 함수에 useCallback을 사용하여 불필요한 재렌더링을 방지

useCallback 문법

const cachedFn = useCallback(fn, dependencies)

onToggleSelectg함수

const onToggleSelect = useCallback((id: CountryWithIsSelected["id"]): void => {
    setCountryInfos((prev) =>
      prev.map((country) =>
        country.id === id
          ? { ...country, isSelected: !country.isSelected }
          : country
      )
    );

    const isSelectedCountry = selectedCountries.find((country) => country.id === id);

    if (!isSelectedCountry) {
      const selectedCountry = countryInfos.find((country) => country.id === id);
      if (selectedCountry) {
        insertData(selectedCountry);
      }
      setSelectedCountries((prev) =>
        selectedCountry ? [...prev, selectedCountry] : prev
      );
    } else {
      const selectedCountry = selectedCountries.find((country) => country.id === id);
      if (selectedCountry) {
        deleteData(selectedCountry);
      }
      setSelectedCountries((prev) => prev.filter((country) => country.id !== id));
    }
  }, [countryInfos, selectedCountries]);

sortCountries함수

const sortCountries = useCallback(
    (sortOption: string): void => {
      setCountryInfos((prev) => {
        const newArr = [...prev];
        switch (sortOption) {
          case "A-Z":
            newArr.sort((a, b) => a.countryName.localeCompare(b.countryName));
            break;
          case "Z-A":
            newArr.sort((a, b) => b.countryName.localeCompare(a.countryName));
            break;
          case "Default":
            return [...countryInfos];
          default:
            return prev;
        }
        return newArr;
      });
    },
    [countryInfos]
  );

useEffect 사용

  • 상태 추가: filteredCountries를 상태로 추가하여 UI 업데이트를 효율적으로 처리.
  • useEffect 사용: countryInfos와 selectedCountries가 변경될 때마다 filteredCountries를 업데이트하도록 useEffect를 사용
  • useEffect훅을 독립적으로 처리하여, 각각의 훅이 특정 상태나 속성의 변화에 맞춰 독립적으로 실행하도록 함.
const [filteredCountries, setFilteredCountries] = useState<CountryWithIsSelected[]>([]);
.
.
.
useEffect(() => {
    const selectedCountryIds = new Set(
      selectedCountries.map((country) => country.id)
    );

    const filtered = countryInfos.filter(
      (country) => !selectedCountryIds.has(country.id)
    );

    setFilteredCountries(filtered);
  }, [countryInfos, selectedCountries]);

트러블 슈팅

문제점

코드를 최적화하는 과정에서 기존에는 문제가 없던 initialCountryInfos가 데이터를 받아오지 못해 빈 배열로 유지되어 Default 버튼이 제대로 작동하지 않는 문제가 생겼다. 비동기 오류라고 예상했고, 따라서 api에서 데이터를 가져오는 기존 로직을 일부 수정해줬다.

해결 방법

  useEffect(() => {
    initialCountryInfos = [...countryInfos];
  }, [countryInfos]);

이전 코드에서는 데이터를 가져와서 setCountryInfos를 해주면서 initialCountryInfos에 각 countryInfo각 요소를 push해줬지만, 이 로직이 데이터를 가져올 때마다 실행되는 부분이 비효율적이라고 생각되어 따로 useEffect로 빼주어 initialCountryInfos를 업데이트해주는 방식으로 수정했다.

그리고 fetchCountryData함수가 있는 useEffect에 의존 배열로 countryInfos를 추가해 initialCountryInfos가 데이터를 가져온 이후에 제대로 업데이트될 수 있도록 했다.

의문점

현재 로직에서 정렬 버튼을 누를 때마다 api가 호출되면서 데이터를 다시 불러오는데 이런 부분은 어떻게 수정할 수 있는지 아직 해결 방법을 찾지 못했다.

하지만 우선 default버튼을 별도로 로직을 설정해줘야한다는 점이 기획 상에서 맞지 않는 부분이라 이 부분에 대한 이해를 하고 넘어가야할 것 같다.

profile
웹 프론트엔드 UXUI

0개의 댓글