[3주차/카사] 워크북 제출합니다.#35
Conversation
|
미션을 수정 중이라 수정 후에 얼른 올리도록 하겠습니다! 😭 |
| @@ -0,0 +1,2 @@ | |||
| export const TMDB_BASE_URL = "https://api.themoviedb.org/3"; | |||
There was a problem hiding this comment.
이렇게 URL도 따로 선언해서 쓸 수가 있었군요! 이렇게 쓰니까 확실히 코드가 깔끔한 거 같아요..! 좋은 방법 알려주셔서 감사합니다!
| ]; | ||
|
|
||
| // 홈 페이지 컴포넌트 | ||
| const HomePage = () => { |
There was a problem hiding this comment.
저는 Homepage 구현을 따로 자세하게 안 했는데 따로 홈페이지를 구현을 해주셨네요! 확실히 홈페이지를 구현하는 게 좋은 것 같습니다! 저도 수정할 때 홈페이지 구현을 해볼까 합니다!
| // 경로와 해당 경로에서 보여줄 컴포넌트를 설정하는 라우터를 생성 | ||
| const router = createBrowserRouter([ | ||
| { | ||
| path: "/", | ||
| element: <RootLayout />, | ||
| // Navbar 아래에 렌더링할 하위 라우트 설정 | ||
| children: [ | ||
| { | ||
| // index: true → 부모의 기본 경로('/')일 때 | ||
| index: true, | ||
| element: <HomePage />, | ||
| }, | ||
| { | ||
| path: "movies/:categoryId", | ||
| element: <MoviesPage />, | ||
| }, | ||
| { | ||
| path: "movies/:categoryId/:movieId", | ||
| element: <MovieDetailPage />, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| path: "*", | ||
| element: <NotFound />, | ||
| }, | ||
| ]); |
There was a problem hiding this comment.
현재는 객체 배열 방식을 이용해 라우팅을 정의하고 있는데 지금처럼 단순 페이지 라우팅 위주라면 Routes, Route 컴포넌트를 이용하는 게 더 깔끔할 것 같습니다!
| 객체 배열 방식 | Route 컴포넌트 방식 | |
|---|---|---|
| 가독성 | 중첩 깊어지면 복잡 | JSX라 직관적 |
| 타입 안전성 | 동일 | 동일 |
| loader/action | ✅ 지원 | ✅ 지원 |
| 코드 분할 | lazy() 사용 가능 |
lazy() 사용 가능 |
| 추천 상황 | loader/action 많이 쓸 때 | 단순 페이지 라우팅 |
There was a problem hiding this comment.
말씀해주신 것처럼 지금처럼 단순 페이지 라우팅 위주라면
Routes, Route를 사용하는 방식이 더 직관적이고 깔끔한 것 같아요!
이번에는 loader/action 같은 기능을 사용한 건 아니지만,
요즘 createBrowserRouter 방식이 권장되기도 해서
미리 익혀보자는 생각으로 적용해봤습니다ㅎ.ㅎ
좋은 피드백 감사합니다!
| import type { MovieCredit, MovieDetail } from "../types/movie"; | ||
|
|
||
| const headers = { | ||
| Authorization: `Bearer ${import.meta.env.VITE_TMDB_ACCESS_TOKEN}`, |
There was a problem hiding this comment.
저는 TMDB 토큰을 별도 환경변수 처리하지 않고 우선 하드코딩으로 적용했는데 보안성과 유지보수성을 고려해 환경변수로 분리하면 좋을 것 같더라구요..!! 저도 다음 프로젝트부터는 환경변수 파일로 빼서 코딩해두겠습니다! 😊
qkrdmsthff
left a comment
There was a problem hiding this comment.
LGTM 카사 ~~ 이번 주차도 수고 많으셨어요!
| disabled={currentPage === totalPages} | ||
| className="px-5 py-2 rounded-full text-sm font-medium bg-gray-800 text-gray-300 border border-gray-600 hover:border-white hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-all" | ||
| > | ||
| 다음 → |
There was a problem hiding this comment.
버튼 내부에 → 와 같은 특수문자가 있을 시 스크린 리더기가 읽기 어려울 수 있습니다! aria-label 을 사용해 보면 좋을 것 같아요!
There was a problem hiding this comment.
조사해보니 특수문자 접근성 처리 방법으로 두 가지가 있었습니다!
- aria-label을 버튼에 추가하는 방식
- 특수문자에 aria-hidden="true"를 적용해 스크린 리더에서 무시하도록 하는 방식
이미 "이전", "다음" 텍스트가 있어서 스크린 리더가 충분히 맥락을 파악할 수 있다고 판단해,
화살표에만 aria-hidden을 적용하는 2번 방식으로 수정했습니다!
<span aria-hidden="true">← </span>이전
다음 <span aria-hidden="true"> →</span>
| const fetchAll = async () => { | ||
| setLoading(true); | ||
| try { | ||
| const [{ data: detail }, { data: credit }] = await Promise.all([ | ||
| axios.get<MovieDetail>( | ||
| `${TMDB_BASE_URL}/movie/${movieId}?language=ko-KR`, | ||
| { headers }, | ||
| ), | ||
| axios.get<MovieCredit>( | ||
| `${TMDB_BASE_URL}/movie/${movieId}/credits?language=ko-KR`, | ||
| { headers }, | ||
| ), | ||
| ]); | ||
| setMovieDetail(detail); | ||
| setMovieCredit(credit); | ||
| setError(null); |
There was a problem hiding this comment.
지금은 간단한 비지니스 로직이여서 괜찮지만, 나중에 로직이 커지거나 하면 해당 api 호출부는 당연히 분리하는 것이 유리합니다! api 호출이 커질수록 유지보수가 어려워지게 돼요!
apis 폴더 생성 후 movie.ts 또는 api.ts 파일을 만들어서 api 호출부를 분리해서 사용해 보아용 ~
There was a problem hiding this comment.
apis/ 폴더를 생성하고 axiosInstance.ts와 movieApi.ts 파일로 분리했습니다! ㅎㅎ
- axiosInstance.ts: baseURL, headers 등 공통 설정을 담은 axios 인스턴스
const axiosInstance = axios.create({
baseURL: TMDB_BASE_URL,
headers: {
Authorization: `Bearer ${import.meta.env.VITE_TMDB_ACCESS_TOKEN}`,
},
});
- movieApi.ts: getMovieDetail, getMovieCredits, getMovieList API 호출 함수
// 영화 목록을 가져오는 API
export const getMovieList = (categoryId: string, page: number) =>
axiosInstance.get<MovieResponse>(`/movie/${categoryId}?language=ko-KR&page=${page}`);
// 영화 상세 정보를 가져오는 API
export const getMovieDetail = (movieId: string) =>
axiosInstance.get<MovieDetail>(`/movie/${movieId}?language=ko-KR`);
// 영화 크레딧 정보를 가져오는 API
export const getMovieCredits = (movieId: string) =>
axiosInstance.get<MovieCredit>(`/movie/${movieId}/credits?language=ko-KR`);훅에서는 axios를 직접 호출하는 대신 movieApi.ts의 함수를 import해서 사용하도록 수정했습니다!
const { data } = await getMovieList(categoryId, page);
✅ 워크북 체크리스트
✅ 컨벤션 체크리스트
📌 주안점