๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป dev

[spotify-api] VINYLIFY : ์Šคํฌํ‹ฐํŒŒ์ด apiํ™œ์šฉํ•œ ๊ฒ€์ƒ‰ + ์žฌ์ƒ ํ”„๋กœ์ ํŠธ(6) tanstack query ์„ค์ •

[์ด์ „๊ธ€] 2024.08.09 - [๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป dev] - [spotify-api] VINYLIFY : ์Šคํฌํ‹ฐํŒŒ์ด apiํ™œ์šฉํ•œ ๊ฒ€์ƒ‰ + ์žฌ์ƒ ํ”„๋กœ์ ํŠธ(5) react router ์„ค์ •

 

[spotify-api] VINYLIFY : ์Šคํฌํ‹ฐํŒŒ์ด apiํ™œ์šฉํ•œ ๊ฒ€์ƒ‰ + ์žฌ์ƒ ํ”„๋กœ์ ํŠธ(5) react router ์„ค์ •

[์ด์ „๊ธ€] 2024.08.08 - [๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป dev] - [spotify-api] VINYLIFY : ์Šคํฌํ‹ฐํŒŒ์ด apiํ™œ์šฉํ•œ ๊ฒ€์ƒ‰ + ์žฌ์ƒ ํ”„๋กœ์ ํŠธ(4) eslint + prettier + commitlint ์„ค์ • (+husky) [spotify-api] VINYLIFY : ์Šคํฌํ‹ฐํŒŒ์ด apiํ™œ์šฉํ•œ ๊ฒ€์ƒ‰ + ์žฌ์ƒ ํ”„

pyotato-dev.tistory.com

์ด์ „ ํฌ์ŠคํŒ…์—๋Š” ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ๋ผ์šฐํŒ…์„ ๊ฐ€๋Šฅ์ผ€ ํ•˜๋Š” react router ์„ค์ •์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋‹ค๋ค˜๋‹ค.
์•ฑ ์ „์ฒด๋ฅผ ๊ฐ์‹ธ์ฃผ๊ธฐ ์œ„ํ•ด Provider๋กœ ๊ฐ์‹ธ์คฌ์—ˆ๋Š”๋ฐ, ์˜ค๋Š˜์€ ์ด ์ตœ์ƒ๋‹จ์— ๊ฐ์‹ธ์ค„ TanstackQuery ์„ค์ •์„ ํ•ด์ฃผ์ž.

๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป Tanstack query๊ฐ€ ๋ญ”์ง€, ์™œ ์“ธ์ง€, ์„ค์ •ํ•ด ์ฃผ๋Š” ๋ฐฉ๋ฒ• ๋“ฑ์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด์ž.

Tanstack Query๋ž€

์ด์ „๋ถ€ํ„ฐ (์ด์   tanstack query๋กœ ๊ฐœ๋ช…ํ•œ) reactquery๋ฅผ ์จ๋ดค์ง€๋งŒ ์“ฐ๋Š” ์ด์œ ์— ๋Œ€ํ•ด์„œ๋Š” ์ •๋ฆฌ๋ฅผ ๋”ฐ๋กœ ํ•˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ ๊ฐ™๋‹ค.

์ด์ „์—๋Š” ๋ฐ”๋กœ axios๋ฅผ ์“ฐ๊ฑฐ๋‚˜ fetch๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™”์—ˆ์ง€๋งŒ, ์ด์ œ๋Š” tanstack query๋ฅผ ์•ˆ ์“ฐ๋Š” ๊ฒŒ ์–ด์ƒ‰ํ•œ ๋Š๋‚Œ์ด ๋“ค ์ •๋„๋‹ค.

 

์ด๋ฒˆ์—๋Š” ์กฐ๊ธˆ ์ƒˆ๋กœ์›Œ์ง„ tanstack query๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์‚ดํŽด๋ณด๊ณ , ์–ด๋–ค ์ด์œ ์—์„œ ์†์ด ๊ณ„์† ๊ฐ€๊ฒŒ ๋˜์—ˆ๋Š”์ง€ ์ •๋ฆฌํ•˜๊ณ ์ž ํ•œ๋‹ค.

 

Tanstack query์€ ํฌ๊ฒŒ ๋‹ค์Œ์˜ ๊ธฐ๋Šฅ๋“ค์„ ์ง€์›ํ•˜๋Š” data-fetching ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค.

  • fetching
  • ์บ์‹ฑ
  • ์„œ๋ฒ„ ์ƒํƒœ์™€ ์‹ฑํฌ ๋งž์ถ”๊ณ  ์—…๋ฐ์ดํŠธ

๋Œ€๋ถ€๋ถ„์˜ ์›น ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์€ fetchํ•˜๋Š” ๋ฐฉ์‹ ๋˜๋Š” ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ ๋ฐฉ์‹์ด opinionated์ด๊ฑฐ๋‚˜ holistic(์œ ๊ธฐ์ )์ด์ง€ ์•Š๋‹ค.

๊ทธ๋ž˜์„œ ๊ฐœ๋ฐœ์ž๋“ค์€ data-fetching์— ๋Œ€ํ•œ ์—„๊ฒฉํ•œ ๊ธฐ์ค€๋“ค์„ ๊ฐ–์ถ˜ meta-framework๋“ค์„ ์ง์ ‘ ๋งŒ๋“ค๊ฑฐ๋‚˜, ์ž์‹  ๋งŒ์˜ data fetching  ๋ฐฉ๋ฒ•์„ ๋งŒ๋“ค์–ด๋‚ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

 

ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋˜๋ฉด, ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์˜ state๊ณผ side-effect์ด ๋’ค์—‰์ผœ ์žˆ๊ฑฐ๋‚˜,

์ผ๋ฐ˜์ ์ธ state ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ œ๊ณตํ•˜๋Š” ๋ฐฉ์‹์„ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด ๋œ๋‹ค.

 

ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”๋ฐ์—๋Š” ์ „ํ†ต์ ์ธ ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํšจ์œจ์ ์ด์ง€๋งŒ ๋น„๋™๊ธฐ(async)๋‚˜ ์„œ๋ฒ„ ์ƒํƒœ์˜ ๊ด€๋ฆฌ์—๋Š” ๋ถ€์ ์ ˆํ•˜๋‹ค. ์ด๋Š” ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์˜ state๊ฐ€ ์ •๋ง ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

์„œ๋ฒ„ ์ƒํƒœ๋Š” 

  • ๊ฐœ๋ฐœ์ž๊ฐ€ ์•Œ๊ฑฐ๋‚˜ ์ œ์–ด๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ๊ณณ์—์„œ ์œ ์ง€๋  ์ˆ˜ ์žˆ๋‹ค.
  • fetch๋‚˜ update์„ ์œ„ํ•ด ๋น„๋™๊ธฐ api๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • "๊ณต์œ "๋œ๋‹ค๋Š” ๊ฑด ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ชจ๋ฅด๋Š” ์‚ฌ์ด์— ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฃผ์˜๋ฅผ ํ•˜์ง€ ์•Š์œผ๋ฉด ์ž ์žฌ์ ์œผ๋กœ "out of date (์ตœ์‹ ์ด ์•„๋‹Œ ์ƒํƒœ)"๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์„œ๋ฒ„ ์ƒํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณผ์ œ๋“ค๋„ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์—์„œ ๋” ๊นŒ๋‹ค๋กญ๋‹ค:

  • ์บ์‹ฑ(caching) 
  •  ์—ฌ๋Ÿฌ ์ค‘๋ณต ์š”์ฒญ์„ ํ•œ ๋ฒˆ์˜ ์š”์ฒญ์œผ๋กœ ์ค„์ด๊ธฐ(Deduping)
  • ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ตœ์‹ ์ด ์•„๋‹Œ ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ
  • ์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ์—…๋ฐ์ดํŠธ ๋ฒ„์ „์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜์˜ํ•˜๊ธฐ
  • ํŽ˜์ด์ง•(pagination)๊ณผ lazy loading ๋ฐ์ดํ„ฐ์™€ ๊ฐ™์€ ์„ฑ๋Šฅ ์ตœ์ ํ™”
  • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์™€ ์„œ๋ฒ„ ์ƒํƒœ์˜ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜
  • structural sharing์œผ๋กœ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜

Tanstack ์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•ด

  • ๋ณต์žกํ•˜๊ณ  ๋งŽ์€ ๋Ÿ‰์˜ ์ฝ”๋“œ๋ฅผ react query ๋กœ์ง ๋ช‡ ์ค„๋กœ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.
  • ์ƒˆ๋กœ์šด ์„œ๋ฒ„ ์ƒํƒœ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ๊ฑฑ์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฌ์šด ๋ฐฉ์‹์œผ๋กœ ์ƒˆ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ง์ ‘ ์œ ์ € ๋๋‹จ์— ์˜ํ–ฅ์„ ๊ฐ€ํ•ด์„œ ๋ฐ˜์‘์„ฑ์ด ์ข‹์€ ์•ฑ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ž ์žฌ์ ์œผ๋กœ bandwidth์™€ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์— ๋„์›€์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ tanstack query๋ฅผ ํ†ตํ•ด์„œ ์˜ˆ์ƒ ๊ฐ€๋Šฅํ•œ ์žฅ์ ๋“ค์€ 

  • ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํ˜„์žฌ ์žฌ์ƒ ๊ณก์— ๋Œ€ํ•œ ์š”์ฒญ์„ ํ•  ๊ฒฝ์šฐ, ํ•ด๋‹น ๋…ธ๋ž˜์— ๋Œ€ํ•œ ๊ฐ€์‚ฌ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” api๊ฐ€ ์‹คํŒจํ•  ์ˆ˜ ์žˆ๋‹ค (ํ•ด๋‹น ๋…ธ๋ž˜์— ๊ฐ€์‚ฌ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, ๋…ธ๋ž˜ ๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ๊ฐ€ ์ž˜๋ชป๋  ๊ฒฝ์šฐ ๋“ฑ). ๊ณ„์† ๊ฒ€์ƒ‰์„ ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ์‹คํŒจ ํšŸ์ˆ˜๊ฐ€ ์ดํ•˜๋กœ๋งŒ ์š”์ฒญ์„ ํ•˜๋„๋ก tanstack query๋กœ์ง์œผ๋กœ ๊ฐ„๋‹จํžˆ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฌดํ•œ ์Šคํฌ๋กค๋ง ๋กœ์ง ๊ฐ„์†Œํ™”
  • ๋ฐ์ดํ„ฐ ์บ์‹ฑ, ์ด์ „ ๋ฐ์ดํ„ฐ ๋ณด์กด : ์•„ํ‹ฐ์ŠคํŠธ ๊ฒ€์ƒ‰ ๋“ฑ์˜ ํŽ˜์ด์ง€๋Š” ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์š”์ฒญํ•˜๋Š” ๋™์•ˆ ์—ฌ๋ฐฑ์„ ๋ณด์—ฌ์ฃผ๊ธฐ๋ณด๋‹ค๋Š” ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ fetchํ•ด์™€์„œ ๋ณด์—ฌ์ค„ ๋•Œ๊นŒ์ง€ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ œ๊ณตํ•˜์—ฌ, ์œ ์ € ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ tanstack query๊ฐ€ ์–ด๋–ค ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•  ์ง€์— ๋Œ€ํ•ด ์‚ดํŽด๋ดค๋‹ค. ์ด์ œ tanstack ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋ณธ ์„ค์ •๋“ค์„ ํ•ด๋ณด์ž.

Tanstack Query ์‚ฌ์šฉ

์„ค์น˜

yarn add @tanstack/react-query

tanstack query dev tools, ํ™”๋ฉด ์šฐ์ธกํ•˜๋‹จ ๊ฐ€์žฅ์ž๋ฆฌ์— ์šฐ์ธก๊ณผ ๊ฐ™์€ ๋ฒ„ํŠผ์ด ์žˆ๋Š”๋ฐ ํด๋ฆญ์‹œ ์ขŒ์ธก๊ณผ ๊ฐ™์ด ๋””๋ฒ„๊น…์— ํ™œ์šฉํ•  ๊ฐœ๋ฐœ๋„๊ตฌ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

๊ฐœ๋ฐœ ๋„๊ตฌ๋„ ์„ค์น˜ํ•ด์ฃผ์ž.

๋ฒˆ๋“ค๋  ๋•Œ process.env.NODE_ENV==='development'์ผ ๊ฒฝ์šฐ์—๋งŒ ํฌํ•จ๋˜๋ฏ€๋กœ ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์— ํฌํ•จ๋  ๊ฑฑ์ •์€ ์•ˆ ํ•ด๋„ ๋˜์ง€๋งŒ, next+13์—์„œ app ๊ฒฝ๋กœ ์‚ฌ์šฉ ์‹œ dev dependency๋กœ ์„ค์ •ํ•ด์•ผ ํ•œ๊ณ  ํ•œ๋‹ค. dev ํ™˜๊ฒฝ์—๋งŒ ์“ฐ๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์•กํŠธ only ํ”„๋กœ์ ํŠธ์ง€๋งŒ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ dev dependency๋กœ ์„ค์ •ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

yarn add @tanstack/react-query-devtools --save-dev
  • tanstackQuery.tsx : ์ตœ์ƒ๋‹จ์„ ์ฟผ๋ฆฌ ํด๋ผ์ด์–ธํŠธ๋กœ ๊ฐ์‹ธ์ค˜์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•œ๋‹ค.
    • ์ด๋•Œ queryClient์˜ ๊ธฐ๋ณธ ์˜ต์…˜์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ฟผ๋ฆฌ staleTime (fresh ํ•จ์„ ์œ ์ง€ํ•  ์‹œ๊ฐ„)์„ 60*100๋กœ ์„ค์ •ํ•ด ์คฌ๋‹ค.
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { ReactNode } from 'react';

const queryClient = new QueryClient({
  defaultOptions: { queries: { staleTime: 60 * 100 } },
});

const isDevEnvironment = import.meta.env.DEV;

const TanstackQuery = ({ children }: { children: ReactNode }) => {
  return (
    <QueryClientProvider client={queryClient}>
      {children}
      {isDevEnvironment && <ReactQueryDevtools />}
    </QueryClientProvider>
  );
};

export default TanstackQuery;
  • providers/index.ts : ์ €๋ฒˆ ํฌ์ŠคํŒ…์— ๋งŒ๋“ค์–ด์ค€ ๋ผ์šฐํ„ฐ๋ฅผ ๊ฐ์‹ธ์ค€๋‹ค.
import Router from './router';
import TanstackQuery from './tanstackQuery';

const Providers = () => {
  return (
    <TanstackQuery> 
      <Router />
    </TanstackQuery>
  );
};

export default Providers;

 


 

https://tanstack.com/query/latest

 

TanStack Query

Instead of writing reducers, caching logic, timers, retry logic, complex async/await scripting (I could keep going...), you literally write a tiny fraction of the code you normally would. You will be surprised at how little code you're writing or how much

tanstack.com