Pokétify_팀프로젝트5_음악추천페이지_2_추천플레이리스트&내플레이리스트만들기_곡리스트

정소현·2024년 10월 14일
0

팀프로젝트

목록 보기
20/50

저번시간 작성했던 accessToken은 개인플레이리스트까지 접근할 수 없는 token이라 새로 accessToken을 구하는 로직을 작성했다.

✨ getPrivateAccessToken

  1. supabase session가져오기
  2. session에 있는 provider_token 을 저장하여 accessToken에 넣어주었다.
  • accessToken이 계속 오류가 나서 왜 그런가 정말 의문이었는데...
    이렇게 쉽게 풀리니 ... 허무하기도 하고 진이 좀 빠졌다 ㅠㅠ😂

☘️ 추천 플레이리스트 나타내기 & 페이지네이션

src > utils > playlistApi.ts


export const recommandPlaylist = async (offset = 0, limit = 20) => {
  const accessToken = await getAccessToken();

  const res = await axios.get(`${BASEURL}/browse/featured-playlists`, {
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "Content-Type": "application/json"
    },
    params: {
      offset: offset,
      limit: limit
    }
  });

  return res.data.playlists;
};

플레이리스트를 나타내는 로직은 저번에 작성했던 accessToken을 가져오는 방법으로 접근이 가능한 api였고 나를 제외한 다른 팀원들은 기본 accessToken을 사용하여 팀원분의 로직을 호출해 넣어주었다.

플레이리스트 - 페이지네이션

spotify developer 에서 하는 방법을 자세히 알려주고 있었다.

  1. 추천 재생목록 컴포넌트에서 state로 offset값을 받아서 상태를 저장하고 한번에 가져오는 데이터의 limit 을 5개로 걸었다.
    offset : 불러올 데이터의 시작지점
    limit : 가져올 데이터의 양

src > components > RecommendPlaylist.tsx

const RecommendPlaylist = ({ onPlaylistSelect }: RecommendPlaylistProps) => {
  const [offset, setOffset] = useState(0);
  const limit = 5;
  1. tanstackQuery를 사용하여 상태를 관리하고 있었음으로 queryKey에 offset값을 추가해주었다.
    => React Query는 queryKey를 기준으로 캐시를 관리한다.
    offset값을 querykey에 포함하지 않으면 서로 다른 페이지의 데이터가 동일한 캐시로 처리될 수 있다. 이로 인해 캐시가 덮여쓰여지거나 잘못된 데이터가 들어올 수 있음으로 querykey에 offset값을 넣음

  2. 페이지에 버튼을 만들어주고 이전 버튼과 다음 버튼에 넣을 로직을 작성해주었다.

  // 다음 페이지로 이동하는 함수
  const handleNextPage = () => {
    if (playlists.items.length === limit) {
      setOffset((prev) => prev + limit);
    }
  };

  // 이전 페이지로 이동하는 함수
  const handlePrevPage = () => {
    setOffset((prev) => Math.max(0, prev - limit));
  };
  1. 그리고 맨 마지막 페이지에서 더 이상 불러올 데이터가 없을 때 넘어가지 않도록 막아주었다.
<button onClick={handleNextPage} disabled={playlists.items.length < limit} className="bg-gray-300 rounded p-2">
          다음
</button>

☘️ 내 플레이리스트 불러오기

src > utils > playlistApi.ts
지난 번에는 일반 accessToken으로 연결했던 부분을 supabase.session을 통해 가져온 provider 로직으로 변경해주었다.

// 내 플레이리스트 불러오기 
export const fetchPlaylist = async (offset = 0, limit = 20) => {
  const accessToken = await getPrivateAccessToken();

  const res = await axios.get(`${BASEURL}/me/playlists`, {
    headers: {
      Authorization: `Bearer ${accessToken}`
    },
    params: {
      offset: offset,
      limit: limit
    }
  });

  return res.data;
};

🔥 Trouble Shooting

☘️ 플레이리스트 재생목록 보여주기

🥵 문제점

  • 플레이리스트 재생목록을 보여주기 위해 props로 계속해서 데이터를 받으며 type을 지정하는 것이 많이 헷갈렸다.
  • 카드마다 클릭했을 때 왼쪽 UI에서 바로 플레이리스트가 나타나야하는데
    잘못된 useQuery의 사용으로 계속 오류가 났다.

✨ 해결방법

내가 생각한 레이아웃은 왼쪽에 선택한 플레이리스트의 재생목록이 나오고 내 플레이리스트를 선택했을 시에는 오른쪽의 검색칸에서 곡을 추가하고 리스트에서 곡이 삭제도 가능하게 만드는 것이었다. 오른쪽에 있는 추천 플레이리스트, 내 플레이리스트를 클릭했을 때 곡들이 나와야하기 때문에
playlist.tsx 페이지 에서
props로 이벤트 전달을 받았다.

  1. useState를 이용해 선택된 카드의 id를 저장시켜주었다.
    src > app > playlist > page.tsx
const PlaylistPage = () => {
  const [selectedPlaylist, setSelectedPlaylist] = useState<string | null>(null);

  // 플레이리스트 선택 핸들러
  const onPlaylistSelect = (id: string | null) => {
    console.log("Selected Playlist ID:", id);
    setSelectedPlaylist(id);
  };
  1. prop로 이벤트를 전달시켜 자식컴포넌트에 변화가 생기면 부모 컴포넌트가 알 수 있도록 내려주었다.
<section className="w-[95%] mx-auto flex">
        <article className="w-[30%] bg-white p-7 flex-grow min-h-[700px]">
          <SongList playlistId={selectedPlaylist} />
        </article>
        <article className="w-[70%] min-h-[80vh] bg-white p-7 flex flex-col justify-between flex-grow gap-3">
          <div className="flex-1">
            <SearchSong />
          </div>
          <div className="flex-1">
            <MyPlaylist onPlaylistSelect={onPlaylistSelect} />
          </div>
          <div className="flex-1">
            <RecommendPlaylist onPlaylistSelect={onPlaylistSelect} />
          </div>
        </article>
      </section>
  1. 각각의 추천플레이리스트와 내 플레이리스트에서 카드가 눌렸을 때 이벤트를 전달할 수 있도록 onClick이벤트를 넣어주었다.
 <ul className="w-[90%] flex list-none gap-4 justify-start">
            {playlists.items.map((playlist) => (
              <li key={playlist.id} onClick={() => onPlaylistSelect(playlist.id)} className="cursor-pointer">
                <PlaylistCard playlist={playlist} />
              </li>
            ))}
          </ul>
  1. 클릭이 발생한 PlaylistCard의 id를 플레이리스트 세부항목을 보여주는 fetch함수에 넣어 불러올 수 있게 하였다.

src > component > SongList.tsx

 const {
    data: playlistData,
    isLoading,
    error
  } = useQuery<PlaylistData>({
    queryKey: ["songList", playlistId],
    queryFn: () => fetchSongsByPlaylist(playlistId!),
    enabled: !!playlistId
  });

Trouble shooting 2

전체적인 Type지정

💥 문제점

  • Tracklist를 가져오는데까지는 성공했는데 가져온 데이터의 정보가 복잡하게 적혀져있었다.
  • Type을 지정하는데 있어서 하나를 넣으면 하나가 오류가 나고 하나를 넣으면 안에 다른 정보가 없다는 메세지가 계속 발생했다.

✨ 해결방법

  • src > types > playlist.ts 에서 interface를 이용해 타입들을 지정해주었는데 내가 최종으로 사용하려고 하는 가장 작은 것에서부터 type을 지정시켜주었다.
  • 구조를 반대로 생각하며 한 단계씩 넣어서 해결했다...!
export interface Track {
  id: string;
  name: string;
  album: AlbumList;
  artists: ArtistList[];
  external_urls: {
    spotify: string;
  };
}

export interface TrackList {
  track: Track;
}

export interface PlaylistData {
  name: string;
  tracks: {
    items: TrackList[];
  };
}

☝️ 느낀점!

점점 Next.js에서 제공하는 app router방식의 routing방식이 익숙해지고 tanstackquery를 사용해 데이터를 가져오고 저장하는 방식이 익숙해지는 것 같다. 처음에는 zustand, context, tanstackquery 하나하나 사용방법 , 이용용도가 많이 헷갈렸는데 그래도 지금은 최소한의 기준을 점점 높여가고 있는 것 같다...!
하나의 트러블 슛팅에 주말내내 월요일인 오늘까지도 정말 많은 시간을 보냈는데 나중엔 휙휙 해결해 나갈 수 있는 내가 될 수 있기를

0개의 댓글