Pokétify_팀프로젝트5_음악추천페이지_3_검색바실시간곡찾기_내플리에추가,플리곡삭제

정소현·2024년 10월 15일
0

팀프로젝트

목록 보기
21/50
post-thumbnail

🌟 검색바 실시간 곡 찾기

지금 개발이 남아있는 기능은 검색바에서 실시간으로 곡제목, 아티스트명으로 곡을 검색하고 선택되어있는 내 플레이리스트에 항목을 추가하는 것이다.

  1. 먼저 spoitify developer에서 제공해주는 항목검색 api를 호출하는 함수를 만들어주었다.
  • params(type)에서 어떤 항목에 대해 검색이 가능하게 할 것인지 정할 수 있다.
  • params(limit)에서 최대 몇개의 데이터까지 불러올 것인지 지정할 수 있다.
    src > utils > playlistApi.ts
// 항목 검색 (곡 & 아티스트)
export const searchMenu = async (query: string) => {
  const accessToken = await getPrivateAccessToken();

  const res = await axios.get(`${BASEURL}/search`, {
    headers: {
      Authorization: `Bearer ${accessToken}`
    },
    params: {
      q: query,
      type: "track,artist",
      limit: 10
    }
  });
  console.log(res.data);
  return res.data.tracks.items;
};
  1. SearchSong.tsx에서 검색 입력을 받기위한 Form을 만들어주고 tanstackquery를 활용해 실시간으로 검색이 반영되도록 로직을 작성해주었다.
const SearchSong = () => {
  const [song, setSong] = useState<string | null>("");
  const {
    data: searchResult,
    isLoading,
    error,
    refetch
  } = useQuery<SearchTrack[]>({
    queryKey: ["searchSong", song],
    queryFn: () => searchMenu(song),
    enabled: !!song
  });

  if (isLoading) {
    return <div>Loading...</div>;
  }
  if (error) {
    return <div>곡을 찾아 오는 도중 에러가 발생했습니다.</div>;
  }
  return (
    <div className="flex flex-col gap-8 pt-4 bg-blue-50 p-4 rounded h-full">
      <h3>SearchSong</h3>
      <input
        type="text"
        placeholder="곡을 입력해주세요"
        value={song}
        onChange={(e) => {
          setSong(e.target.value);
          refetch();
        }}
        className="w-[20rem] h-[2rem]"
      />
      <div>

💥 Trouble Shooting

🥵 문제점 : 원하는 대로 검색을 하면 실시간으로 데이터가 반영되어 결과가 나타났다. 하지만 내가 입력을 하는동안 계속해서 UI가 깜빡이고 이것이 불편하게 느껴졌다.

🌟 해결방법

  • Throttling을 활용해 결과가 실시간으로 반영될 수 있도록 하였다.
// Throttle 함수
const useThrottle = <T,>(value: T, limit: number): T => {
  const [throttledValue, setThrottledValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setThrottledValue(value);
    }, limit);

    return () => {
      clearTimeout(handler);
    };
  }, [value, limit]);

  return throttledValue;
};
  • Throttling 함수를 활용해 staletTime을 지정해 데이터 불러오기
const SearchSong: React.FC<{ playlistId: string }> = ({ playlistId }) => {
  const [song, setSong] = useState<string>("");
  const throttledSong = useThrottle(song, 300);
  const queryClient = useQueryClient();

  const { data: searchResult = [], error } = useQuery<SongMenu[], Error>({
    queryKey: ["searchSong", throttledSong],
    queryFn: () => searchMenu(throttledSong),
    enabled: !!throttledSong,
    staleTime: 5000
  });

💥 Trouble Shooting 2

  • 트랙을 나의 플레이리스트에 추가하고 삭제하는 로직을 분명히 맞게 작성했다고 생각했음에도 불구하고 계속해서 오류가 발생하였다.
  • 결론적으로 2가지 이유가 있었다. 별 게 아니라고 생각할 수 있지만 엄청난 문제였다...

🥵 문제점

  1. props함수명을 잘못 받았다.
    나는 props-drilling을 활용해 클릭된 재생목록의 id를 받아왔는데 작업을 하며 부모컴포넌트에서 자식컴포넌트로 받을 때 보냈던 명칭과 다르게 받아 값이 들어오고 있지 않은 것이었다.
    무한 console.log를 찍으면서 발견...

  2. 내가 사용하는 api들은 내가 작성한 privateaccessToken을 가져와서 사용하게 되는 것이었다.
    오류메세지를 확인해보니 계속해서 403에러가 났다.
    어떤 이유인지 몰라 다시한번 spotify developer docs를 하나하나 정독했다. 잘 찾아보니 이렇게 나와있었다.

supabase로 로그인을 하는 로직에서 미리 scope를 정해주어야하는 것이었다.
playlist-modify-private playlist-modify-public" 를 추가한 이후에 바로 반영이 되었다...


  // Login handler
  const handleSpotifyLogin = async () => {
    const { error } = await supabase.auth.signInWithOAuth({
      provider: "spotify",
      options: {
        redirectTo: "http://localhost:3000/auth/callback",
        scopes:
          "user-read-private playlist-read-private playlist-read-collaborative playlist-modify-private playlist-modify-public"
      }
    });

🌼 느낀 점

로직을 작성하기 이전에 API를 제공해주는 곳에서 걸어놓은 조건들에 조금 더 집중해야겠다는 생각을 많이 했다. 그래도 해결했을 때의 그 기쁨이 힘듦을 씻어주는 것 같다..!!!


☝️ 새롭게 알게 된 것

1.

Throttling : 짧은 시간동안 연속해서 발생한 이벤트들을 일정 시간 단위(delay)로 그룹화하여 처음 또는 마지막 이벤트 핸들러만 호출하도록 하는 것!

Debouncing : 짧은 시간동안 발생한 이벤트를 호출하지 않다가 마지막 이벤트로부터 일정시간(delay)이후에 한번만 호출하도록 하는 것

ex) 스크롤 이벤트 - 일정시간동안 스크롤 이벤트가 여러번 발생하더라도 마지막 스크롤 위치만 사용하여 처리됨 / 자동완성 기능

Throttling, Debouncing 차이점

  • Debounce는 입력 값이 변경될 때마다 직접 반영되지 않고 입력이 멈춘 후에 일정 시간이 지난 후 반영
  • 이벤트 핸들러 호출 빈도
  • 이벤트를 언제 발생 시킬지의 시점 차이!

2.

나는 useQuery와 useMutation invalidateQueries (tanstackQuery)를 활용해 데이터를 불러왔는데 곡을 검색하고 추가버튼을 눌렀을 때 실시간으로 반영되게 하는 과정에서 내가 다른 tsx파일에서 선언한 queryKey를 이용해 invalidateQueries 실시간으로 처리되게 할 수 있다는 것을 알았다. 생각해보면 전체를 아우르고 있는데 잘 쓰지 않아 잊고 있었다.

  // 곡 추가 뮤테이션
  const addTrackMutation = useMutation({
    mutationFn: (uri: string) => addPlaylist(playlistId, uri),
    onSuccess: () => {
      queryClient.invalidateQueries(["getPlaylistTracks", playlistId]);
      setSong("");
    }
  });

0개의 댓글