DEVLOG
Next.js ํ๋ก์ ํธ :: Open API (TMDB), React-Query ๋ณธ๋ฌธ
๐ ๋ชฉ์ฐจ
๐ TMDB Open API
์ด๋ฒ ํ๋ก์ ํธ์์๋ TMDB API์์ ์ ๊ณตํ๋ Open API๋ฅผ ์ฌ์ฉํด ์ํ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ฌ ์์ ์ด๋ค.
API key ๋ฐ๊ธ
๋ฐ์ดํฐ๋ฅผ ์ด์ฉํ๋ ค๋ฉด TMDB ์ฌ์ดํธ - ์ค์ - api์์ api key๋ฅผ ๋ฐ๊ธ๋ฐ์์ผํ๋ค.
https://api.themoviedb.org/3/movie/{movie_id}?api_key=<<api_key>>&language=en-US
API docs
TMDB API docs์ ์ค๋น๋์ด ์๋ api๋ค์ ์ด๊ฒ์ ๊ฒ ์กฐํํด๋ณด๋ฉฐ ์ฌ์ฉํ api๋ค์ ์ฐพ์๋๋ค!์๊ฐ๋ณด๋ค ๋ค์ํ api๋ค์ด ์์ด์ ์ฌ๋ฌ ๊ธฐ๋ฅ์ ๊ฐ์ง ํ์ด์ง๋ฅผ ๋ง๋ค ์ ์์ ๊ฒ ๊ฐ๋ค.
๐ React-Query
๋ฐ์ดํฐ fetching ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ด๋ฒ์ ํ๋ฒ์ฏค ์ฌ์ฉํด๋ณด๊ณ ์ถ์๋ react-query
๋ฅผ ์ฌ์ฉํด๋ณด๊ธฐ๋ก๋ก ํ๋ค. ์ฌ๋ฌ๊ฐ์ง ์ฅ์ ์ด ์์ง๋ง ์ฃผ๋ก ์ด๋ฌ์ด๋ฌํ ์ฅ์ ๋๋ฌธ์ ์ต๊ทผ์ ๋ง์ด ๋ ์ค๋ฅด๊ณ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๊ณ ํ๋ค.
- ์บ์ฑ
- get์ ํ ๋ฐ์ดํฐ์ ๋ํด update๋ฅผ ํ๋ฉด ์๋์ผ๋ก get์ ๋ค์ ์ํํ๋ค. (์๋ฅผ ๋ค๋ฉด ๊ฒ์ํ์ ๊ธ์ ๊ฐ์ ธ์์ ๋ ๊ฒ์ํ์ ๊ธ์ ์์ฑํ๋ฉด ๊ฒ์ํ ๊ธ์ getํ๋ api๋ฅผ ์๋์ผ๋ก ์คํ)
- ๋ฐ์ดํฐ๊ฐ ์ค๋ ๋์๋ค๊ณ ํ๋จ๋๋ฉด ๋ค์ get (invalidateQueries)
- ๋์ผ ๋ฐ์ดํฐ ์ฌ๋ฌ๋ฒ ์์ฒญํ๋ฉด ํ๋ฒ๋ง ์์ฒญํ๋ค. (์ต์ ์ ๋ฐ๋ผ ์ค๋ณต ํธ์ถ ํ์ฉ ์๊ฐ ์กฐ์ ๊ฐ๋ฅ)
- ๋ฌดํ ์คํฌ๋กค (Infinite Queries (opens new window))
- ๋น๋๊ธฐ ๊ณผ์ ์ ์ ์ธ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๋ค.
- react hook๊ณผ ์ฌ์ฉํ๋ ๊ตฌ์กฐ๊ฐ ๋น์ทํ๋ค.
์ด๋ฌํ ์ฅ์ ์ค ๋ฌดํ ์คํฌ๋กค์ ๊ตฌํํ๊ธฐ ์ํด ํฐ ์ฅ์ ์ด ๋๊ปด์ง ๊ฒ ๊ฐ์ react-query
๋ฅผ ์ ํํ๋ค.
์ค์น
npm i react-query
_app.tsx ์ธํ
_app.tsx
์ ๋จผ์ QueryClientProvider๋ฅผ ์ธํ
ํด์ผํ๋ค.
//base
import type { AppProps } from "next/app";
import Head from "next/head";
//libraries
import { QueryClientProvider, QueryClient } from "react-query";
//style
import "../styles/globals.css";
function MyApp({ Component, pageProps }: AppProps) {
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>MERORIIVING</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<Component {...pageProps} />
</QueryClientProvider>
);
}
export default MyApp;
useQuery
์กฐํ๋ useQuery๋ฅผ ์ด์ฉํ๋ค.
export const getMovieList = async (list: string, page = 1) => {
const { data } = await axios.get(
`https://api.themoviedb.org/3/movie/${list}?api_key=${process.env.NEXT_PUBLIC_API_KEY}&language=ko-KR&page=${page}`
);
return data;
};
export const getMovieInfo = async (id: string) => {
const { data } = await axios.get(
`https://api.themoviedb.org/3/movie/${id}?api_key=${process.env.NEXT_PUBLIC_API_KEY}&language=ko-KR`
);
return data;
};
...
const { isLoading:listLoading, data:listData } = useQuery("movieData", () => getMovieList('popular'));
const { isLoading:movieLoading, data:movieData } = useQuery("movie", () => {
return getMovieInfo(params.id);
});
โ ์์ธํ์ด์ง ์ธํ ์ ๊ฒช์ ์ด์
โ โโโ pages
โ โโโ detail
โ โ โโโ [id].tsx
โ โโโ _app.tsx
โ โโโ _document.tsx
โ โโโ index.tsx
detail์ subpage๋ฅผ ๊ฐ๋ ๊ตฌ์กฐ๋ก ์์ ํ์ฌ ๋ฉ์ธ์์ ์นด๋ ํด๋ฆญ์ detail/[id]๋ก Link๋ฅผ ์ฐ๊ฒฐํด์ฃผ์๋ค.
<Link href={`/detail/${id}`}>
<Poster posterUrl={imageUrl(poster_path)} />
<div>{title}</div>
</Link>
๐ฌ ๊ฒช์ ์ด์ Next.js ๋ผ์ฐํธ์ฟผ๋ฆฌ undefined ์ค๋ฅ
๐ ๊ฒฐ๊ณผ
๋ฉ์ธํ์ด์ง
์์ธํ์ด์ง
๐ Next?
๊ทธ๋ฐ๋ฐ,, ์๋ฌด๋๋ ๋ด๊ฐ ์ฌ์ฉํ๋ api์ ๊ฒฝ์ฐ ์ค์๊ฐ์ผ๋ก ๋ณํ๋ ๋ฐ์ดํฐ๋ ์๋๊ณ , SEO์ธก๋ฉด์์ ์ ๋ฆฌํ ๊ฒ์ด ์ข์ ํ์ด์ง๋ก ์ธํ
ํ๋๊ฒ ์ข์ง ์์๊น? ํ๋ ์๊ฐ๊ณผ ํจ๊ป Next.js๋ฅผ ์ฌ์ฉํ๊ฒ ๋ ์ด์ ์ค ํ๋์ธ SSR๋ก ๋ฐ์ดํฐ๋ฅผ ์ธํ
ํ๊ณ ์ถ์ด์ก๋ค.
๊ทธ๋์ ๋ฐ์ดํฐ๋ฅผ SSR๋ก ์ธํ
ํ๊ธฐ์ํด getServerSideProps๋ฅผ ๋์
ํ ์์ ์ด๋ค.
'frontend > next.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Next.js ํ๋ก์ ํธ :: infinite scroll ๊ตฌํํ๊ธฐ (0) | 2023.07.12 |
---|---|
Next.js ํ๋ก์ ํธ :: carousel ๊ตฌํํ๊ธฐ (0) | 2023.06.22 |
Next.js ํ๋ก์ ํธ :: getServersideProps (0) | 2023.06.22 |
Next.js ํ๋ก์ ํธ :: ์ธํ (0) | 2023.06.22 |
Next.js ์์ํ๊ธฐ (0) | 2023.06.19 |