[TIL] 230831

이세령·2023년 8월 31일
0

TIL

목록 보기
94/118

Nextjs

영화 콘텐츠 목록 페이지

  • 하위 컴포넌트인 검색과 정렬 select를 기준으로 영화 목록을 보여줘야 해서 props로 내려주었다.
const [sortingOption, setSortingOption] = useState<string>('popularity'); // 정렬 옵션
  const [searchType, setSearchType] = useState('movie'); // 검색 filter 옵션
  const [searchMovieValue, setSearchMovieValue] = useState('');

return (
    <div>
      <div className="flex justify-between h-20">
        <Sort sortingOption={sortingOption} setSortingOption={setSortingOption} />
        <Search
          searchMovieValue={searchMovieValue}
          setSearchMovieValue={setSearchMovieValue}
          searchType={searchType}
          setSearchType={setSearchType}
        />
      </div>
      <div className="p-8">{contents}</div>
      {currentPage < dataList?.total_pages && ( // 다음 페이지가 있는 경우에만 더보기 버튼 표시
        <div onClick={fetchMore} className="bg-blue-700 cursor-pointer text-center py-2 text-white">
          더보기
        </div>
      )}
    </div>
  );
  • 렌더링 기준
    정렬 옵션이나 페이지가 늘어나면 추가된 내용을 렌더링 해주어야 하기에 현재 페이지, 검색하면 새로운 데이터를 불러와야 하기에 검색어를 기준으로 렌더링 되게 의존성 배열을 설정했다.
useEffect(() => {
    if (searchMovieValue) {
      const sortedMovies = sortData(filteredData, sortingOption);
      setFilterefData(sortedMovies);
    } else {
      // 초기화
      setDataList([]);
      setCurrentPage(1);
      fetchMovieData(1);
    }
  }, [sortingOption]);

  useEffect(() => {
    fetchMovieData(currentPage);
    console.log('검색', searchMovieValue);
  }, [currentPage, searchMovieValue]);
  • url 요청이 아닌 가져온 데이터 내에 정렬
    전체 목록에서는 &sort_by=~ 이런식으로 url을 수정하여 정렬된 상태로 가져올 수 있지만 그 외에는 수동으로 정렬해주어야 하기 때문에 함수를 추가했다.
const sortData = (data: TMDBSearchMovie[], sortingOption: string): TMDBSearchMovie[] => {
    switch (sortingOption) {
      case 'popularity':
        return data.slice().sort((a, b) => b.popularity - a.popularity);
      case 'primary_release_date':
        return data.slice().sort((a, b) => dayjs(b.release_date).diff(dayjs(a.release_date)));
      case 'vote_average':
        return data.slice().sort((a, b) => b.vote_average - a.vote_average);
      default:
        return data;
    }
  };
  • 데이터 요청
    검색어 존재 여부, 검색 필터링, 정렬 등에 따라 경우의 수가 나뉘기 때문에 다음과 같이 코딩하였다. 인물 검색의 경우 데이터 형식이 달라서 한번 더 나누었다.
const fetchMovieData = async (page: number) => {
    if (searchMovieValue) {
      // 검색 했을 때
      const data = await contentPageGetDataSearch(searchMovieValue, searchType, page);
      setDataList(data);

      if (searchType === 'movie') {
        const results = data.results;
        if (page === 1) {
          setFilterefData([...results]);
        } else {
          setFilterefData([...filteredData, ...results]);
        }
      } else {
        const results = data.results[0].known_for;
        if (page === 1) {
          setFilterefData([...results]);
        } else {
          setFilterefData([...filteredData, ...results]);
        }
        console.log('영화데이터', results);
      }
    } else {
      // 검색 x
      const data = await contentPageGetDataDiscover(sortingOption, formattedCurrentDate, page);
      setDataList(data);
      const results = data.results;
      if (page === 1) {
        setFilterefData([...results]);
      } else {
        setFilterefData([...filteredData, ...results]);
      }
    }
  };

문제해결

옵션이 변경될 때 렌더링 할때마다 기존 데이터에 추가되어 보여주는 현상 수정

 const fetchMovieData = async (page: number) => {
    if (searchMovieValue) {
      // 검색 했을 때
      const data = await contentPageGetDataSearch(searchMovieValue, searchType, page);
      setDataList(data);
      const results = data.results;

       setFilterefData([...filteredData, ...results]);
    } else {
      // 검색 x
      const data = await contentPageGetDataDiscover(sortingOption, formattedCurrentDate, page);
      setDataList(data);
      const results = data.results;
      
        setFilterefData([...filteredData, ...results]);
      
    }
  };

useEffect(() => {
    // 초기화
    setFilterefData([]);
    // console.log(filteredData);
    setDataList([]);
    setCurrentPage(1);
    fetchMovieData(1);
  }, [sortingOption, searchMovieValue]);

처음에 저렇게 초기화 후, 다시 fetch하면 될줄 알았는데 한번에 처리해서 그런가 기존 데이터에 계속 붙어서 나왔다.

page가 1일때만 데이터가 처음부터 나오도록 수정하였다.

const fetchMovieData = async (page: number) => {
    if (searchMovieValue) {
      // 검색 했을 때
      const data = await contentPageGetDataSearch(searchMovieValue, searchType, page);
      setDataList(data);
      const results = data.results;

      if (page === 1) {
        setFilterefData([...results]);
      } else {
        setFilterefData([...filteredData, ...results]);
      }
    } else {
      // 검색 x
      const data = await contentPageGetDataDiscover(sortingOption, formattedCurrentDate, page);
      setDataList(data);
      const results = data.results;
      if (page === 1) {
        setFilterefData([...results]);
      } else {
        setFilterefData([...filteredData, ...results]);
      }
    }
  };

useEffect(() => {
    // 초기화
    setDataList([]);
    setCurrentPage(1);
    fetchMovieData(1);
  }, [sortingOption, searchMovieValue]);

리팩토링할 때, query를 사용하여 fetching을 더 쉽게 변경하자

React query의 서버 관리 장점

  1. fetching : 서버에서 데이터 받아오기
  2. caching : 서버에서 받아온 데이터를 따로 보관해서 동일한 데이터가 단 시간 내에 다시 필요할 시 서버요청없이 보관된 데이터에서 꺼내쓰기
  3. synchronizing : 서버상의 데이터와 보관 중인 캐시 데이터(서버상태)를 동일하게 만들기 (동기화)
  4. updating : 서버 데이터 변경 용이 (mutation & invalidateQueries)

더보기를 했을 경우에 검색을 하면 검색한 결과가 제대로 나타나지 않는다. 이 문제를 해결하고 슬라이더 구현과 핫한 토픽출력만 하면 될 것 같다.

profile
https://github.com/Hediar?tab=repositories

0개의 댓글