somn45 / mucketlist

React, Typescript, Spotify API를 이용해 좋아하는 장르의 곡을 지속적으로 추적, 몰랐던 명곡을 저장할 수 있는 APP
0 stars 0 forks source link

로그인 직후에 트랙의 장르가 불러와지지 않는 현상이 발생합니다. #4

Closed somn45 closed 2 years ago

somn45 commented 2 years ago

현재 mucketlist 앱은 사용자의 로그인이 확인되면 Home 컴포넌트에서 트랙의 장르를 서버에서 get하여 불러오는 구조를 가지고 있습니다. 그런데 로그인 하자마자 1~2번 정도 장르가 불러오지 않는 현상이 일어납니다. 심지어 서버를 먼저 가동해도 똑같은 현상이 일어납니다. 다음은 장르 출력과 관련된 코드 내용입니다.

function Home({ selectedGenres, tracks, settings }: HomeProps) {
  const [genres, setGenres] = useState<string[]>([]);
  useEffect(() => {
    getSpotifyGenres();
    if (!cookies.get('F_UID')) navigate('/login');
  }, []);

  useEffect(() => {
    const tracks = localStorage.getItem('tracks');
    if (!tracks) return;
    setSortedTracks(JSON.parse(tracks));
  }, [settings]);

  const getSpotifyGenres = async () => {
    const accessToken = cookies.get('accessToken');
    const response = await axios.post(`http://localhost:3001/genres`, {
      accessToken: accessToken,
    });
    setGenres(response.data.genres);
    setLoading(false);
    setIsOpenSettings(true);
  };
}
...
     <form>
        {loading ? (
          <h2>장르 목록을 불러오는 중입니다.</h2>
        ) : (
          <>
            {genres.map((genre) => (
              <Genre key={genre} genre={genre} />
            ))}
          </>
        )}
        <input
          type="submit"
          value="Search your favorite genres"
          onClick={onClick}
        />
      </form>

장르가 불러와지지 않는 경우 서버에서 다음과 같은 오류 내용이 전송됩니다.

WebapiRegularError: An error occurred while communicating with Spotify's Web API.
Details: No token provided.
somn45 commented 2 years ago

해결했습니다. accessToken이 동기적으로 쿠키에 넣어지는게 아니기 때문에 getSpotifyGenre 함수를 실행할때에는 accessToken이 존재하지 않으므로 위의 버그가 발생했던 것이었습니다. 따라서 accessToken을 쿠키에 넣는 과정에서 accessToken을 redux 상태에 추가하여 글로벌하게 관리할 수 있도록 했습니다. 그리고 만약 accessToken이 쿠키에 들어온 것을 확인하면 getSpotifyGenre 함수가 들어있는 useEffect를 다시 실행하도록 코드를 수정했습니다.

// SpotifyAuth 컴포넌트
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Cookies } from 'react-cookie';
import { useDispatch } from 'react-redux';
import { addAccessToken } from './store/store';

const code = new URLSearchParams(window.location.search).get('code');
const cookies = new Cookies();

function SpotifyAuth() {
  const dispatch = useDispatch();
  const [accessToken, setAccessToken] = useState('');
  useEffect(() => {
    const accessToken = cookies.get('accessToken');
    if (accessToken) {
      dispatch(addAccessToken(accessToken));
      return;
    }
    if (!code) return;
    requestTokens(code);
  }, []);

  useEffect(() => {
    if (accessToken) return;
    refreshAccessToken(accessToken);
  }, [accessToken]);

  const requestTokens = async (code: string): Promise<void> => {
    try {
      const response = await axios.post('http://localhost:3001/spotify/auth', {
        code: code,
        fuid: cookies.get('F_UID'),
      });
      dispatch(addAccessToken(response.data.accessToken));
      window.location.href = '/';
    } catch (error) {
      console.log(error);
    }
  };

  const refreshAccessToken = async (accessToken: string): Promise<void> => {
    const firebaseUid = cookies.get('F_UID');
    const response = await axios.post('http://localhost:3001/spotify/refresh', {
      firebaseUid: firebaseUid,
    });
    dispatch(addAccessToken(response.data.accessToken));
  };
  return <div></div>;
}

export default SpotifyAuth;
// Home 컴포넌트
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Cookies } from 'react-cookie';
import axios from 'axios';
import { connect, useDispatch } from 'react-redux';
import Genre from '../components/Genre';
import Settings, { TrackState } from './Settings';
import Tracks from './Tracks';
import { clearSettings, createTracks } from '../store/store';

interface HomeProps {
  accessToken: string;
  selectedGenres: string[];
  settings: string;
}

interface HomeStates {
  accessToken: string;
  genre: string[];
  tracks: TrackState[];
  settings: string;
}

const cookies = new Cookies();

function Home({ selectedGenres, accessToken, settings }: HomeProps) {
  console.log(accessToken);
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const [genres, setGenres] = useState<string[]>([]);
  const [sortedTracks, setSortedTracks] = useState<TrackState[]>([]);
  const [loading, setLoading] = useState(true);
  const [isOpenSettings, setIsOpenSettings] = useState(false);
  useEffect(() => {
    getSpotifyGenres();
    if (!cookies.get('F_UID')) navigate('/login');
  }, [accessToken]);

  useEffect(() => {
    const tracks = localStorage.getItem('tracks');
    if (!tracks) return;
    setSortedTracks(JSON.parse(tracks));
  }, [settings]);

  const getSpotifyGenres = async () => {
    const accessToken = cookies.get('accessToken');
    const response = await axios.post(`http://localhost:3001/genres`, {
      accessToken: accessToken,
    });
    setGenres(response.data.genres);
    setLoading(false);
    setIsOpenSettings(true);
  };

  const onClick = async (e: React.MouseEvent<HTMLInputElement>) => {
    e.preventDefault();
    if (selectedGenres.length === 0) {
      return;
    }
    const genres = JSON.stringify(selectedGenres);
    const accessToken = cookies.get('accessToken');
    const response = await axios.get(
      `http://localhost:3001/search?accessToken=${accessToken}&genre=${genres}`
    );
    console.log(response.data.tracks);
    dispatch(createTracks(response.data.tracks));
    dispatch(clearSettings(''));
  };
... ... 

const mapStateToProps = (state: HomeStates) => {
  return {
    accessToken: state.accessToken,
    selectedGenres: state.genre,
    tracks: state.tracks,
    settings: state.settings,
  };
};

export default connect(mapStateToProps)(Home);