somn45 / mucketlist

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

No routes matched location "/" 경고메시지 발생 #5

Closed somn45 closed 2 years ago

somn45 commented 2 years ago

찜한 트랙리스트를 사용자에게 보여주기 위해 CustomPlayLisy라는 컴포넌트를 중첩 라우팅 설정을 했습니다. 그런데 중첩 라우팅을 위한 라우터 설정 후 다음과 같은 경고메시지가 나옵니다.

No routes matched location "/"  경고메시지 발생

메시지의 내용으로는 주소가 /와 일치하는 라우터가 없다고 나오네요. mucketlist 앱에서는 '/'주소가 Home 컴포넌트의 주소로 되어있습니다. 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 {
  selectedGenres: string[];
  tracks: TrackState[];
  settings: string;
}

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

const cookies = new Cookies();

function Home({ selectedGenres, tracks, settings }: HomeProps) {
  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');
  }, []);

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

  const getSpotifyGenres = async () => {
    const accessToken = cookies.get('accessToken');
    if (!accessToken) return console.log('not token');
    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(''));
  };
  return (
    <div>
      <h2>Home</h2>
      <form>
        {loading ? (
          <h2>장르 목록을 불러오는 중입니다.</h2>
        ) : (
          <>
            {genres.map((genre) => (
              <Genre key={genre} genre={genre} />
            ))}
          </>
        )}
        <input
          type="submit"
          value="Search your favorite genres"
          onClick={onClick}
        />
      </form>
      {isOpenSettings ? <Settings /> : null}
      {sortedTracks ? <Tracks tracks={sortedTracks} /> : null}
    </div>
  );
}

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

export default connect(mapStateToProps)(Home);
somn45 commented 2 years ago

경고 메시지의 원인을 찾지는 못했으나 해결법은 찾았습니다. React Router의 Outlet을 이용하여 해결했습니다.

// App.tsx
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { Cookies } from 'react-cookie';
import Home from './pages/Home';
import Login from './pages/Login';
import Join from './pages/Join';
import Header from './pages/Header';
import SpotifyAuth from './SpotifyAuth';
import CustomPlayList from './pages/CustomPlayList';

const cookies = new Cookies();

function App() {
  return (
    <Router>
      <SpotifyAuth />
      {cookies.get('F_UID') ? <Header /> : null}
      <Routes>
        <Route path="/" element={<Home />}>
          <Route path="/track/custom" element={<CustomPlayList />} />
        </Route>
        <Route path="/login" element={<Login />} />
        <Route path="/Join" element={<Join />} />
      </Routes>
    </Router>
  );
}

export default App;
// Home.tsx
import React, { useEffect, useState } from 'react';
import { Outlet, 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, getAccessToken } from '../store/store';
...
const cookies = new Cookies();

function Home({ selectedGenres, accessToken, settings }: HomeProps) {
...
  return (
    <div>
      <Outlet />
      <h2>Home</h2>
      <form>
        {loading ? (
          <h2>장르 목록을 불러오는 중입니다.</h2>
        ) : (
    ...
    </div>
  );
}

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

export default connect(mapStateToProps)(Home);

Outlet이란 Outlet 태그가 포함되어 있는 컴포넌트에서 중첩 라우터의 경로로 이동하는 컴포넌트로 이동하려 할 때 path가 일치하면 중첩 라우터의 컴포넌트를 불러오고 일치하지 않으면 불러오지 않는 태그입니다. 원래에는 중첩 라우팅을 위해 Home의 path가 "/*"였으나 대신 다른 대안인 Home의 path는 "/"으로 교체하고 대신 Outlet을 사용하는 방식으로 바꿨습니다.

일단 경고 메시지의 출력은 나타나지 않았으나 아직 문제점의 원인을 찾지 못했으므로 close하지 않고 문제점 발견 시에 다시 comment를 작성할 계획입니다.