๐Ÿ”ญ SWR ๐Ÿ”ญ

๋ฐ•์ƒ์€ยท2022๋…„ 6์›” 18์ผ
0

๐ŸŽ ๋ถ„๋ฅ˜ ๐ŸŽ

๋ชฉ๋ก ๋ณด๊ธฐ
1/16

swr์˜ ์ž์„ธํ•œ ์„ค๋ช…์€ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฝ๋Š” ๊ฒƒ์ด ๋” ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ•ด์„œ ์ „์ฒด์ ์œผ๋กœ ์ •๋ฆฌํ•จ๊ณผ ๋™์‹œ์— ์ดํ•ดํ•œ ๋ถ€๋ถ„์— ๋Œ€ํ•œ ๋ณต์Šต์ฐจ์›์—์„œ ์ž‘์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ•น๏ธ SWR์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

SWR์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ํŒจ์น˜ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ ํŒจ์น˜๋Š” fetch๋‚˜ axios๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ๋„ ์ถฉ๋ถ„ํžˆ ๊ฐ€๋Šฅํ•œ๋ฐ ๊ตณ์ด ์ถ”๊ฐ€๋กœ ๊ณต๋ถ€๊ฐ€ ํ•„์š”ํ•œ SWR์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด์„œ ์ œ๊ฐ€ ๋Š๋‚€๋Œ€๋กœ ์ ์–ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ผ๋‹จ ๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜์ž๋ฉด fetch๋‚˜ axios๋Š” ๋ฐ์ดํ„ฐ ํŒจ์นญ์˜ ๊ธฐ๋Šฅ ์ด์™ธ์—๋Š” ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์€ ์ „ํ˜€ ์—†๋Š” ๊ฑธ๋กœ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฌผ๋ก  API๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ง์ „๊ณผ ์งํ›„์— ์ธํ„ฐ์…‰ํ„ฐ๋กœ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ๊ทผ๋ณธ์ ์œผ๋กœ API๋ฅผ ์š”์ฒญํ•˜๋Š” ์—ญํ• ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ SWR์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ๋‚œ ์ดํ›„์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”๋ฐ ์—„์ฒญ๋‚œ ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
ํ‚ค์›Œ๋“œ๋กœ๋งŒ ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋ฐ์ดํ„ฐ ์บ์‹ฑ, ์ž๋™ ๊ฐฑ์‹ , ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋“ฑ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ธฐ ํž˜๋“  ๋งŽ์€ ๊ธฐ๋Šฅ๋“ค์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ œ๊ณตํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— SWR์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ๊ฐ€ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ดํ›„ ๋‚ด์šฉ๋“ค์€ ์ด๋Ÿฐ ์ด์ ๋“ค๊ณผ ์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์ง์ ‘ ๊ฒฝํ—˜ํ•ด ๋ณธ ๋Œ€๋กœ ์ •๋ฆฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
( ์ถ”๊ฐ€๋กœ typescript ๊ธฐ์ค€์œผ๋กœ ์ •๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. )

๐Ÿ”Ž SWR ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•๊ณผ ์บ์‹ฑ

  • ์„ค์น˜
npm i swr
  • ์‚ฌ์šฉ
import useSWR from "swr";

type UserResponse = {
  id: number;
  name: string;
  email: string;
  // ํƒ€์ž…์ด ๋งŽ์•„์„œ ์ผ๋ถ€๋ถ„๋งŒ ์ž‘์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
}

const fetcher = (url: string) => fetch(url).then(res => res.json());

const Component = () => {
  const { data, error } = useSWR<UserResponse>("https://jsonplaceholder.typicode.com/users/1", fetcher)
  
  if(error) return <h3>Failed to load<h3>;
  if(!data && !error) return <h3>Loading<h3>;
  
  return (
    <section>
      <div>{data.name}</div>
      <div>{data.email}</div>
    </section>
  )
}

์ผ๋ฐ˜์ ์œผ๋กœ useSWR<๋ฐ˜ํ™˜ํ•  ๋ฐ์ดํ„ฐ ํƒ€์ž…>("์š”์ฒญ url", fetcher) ํ˜•์‹์œผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

useSWR()์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž์ธ url์€ ์บ์‹œํ•˜๊ธฐ์œ„ํ•œ ์œ ์ผํ•œ key๊ฐ€ ๋จ๊ณผ ๋™์‹œ์— fetcher()์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์บ์‹œ ํ•˜๊ธฐ ์œ„ํ•œ ์œ ์ผํ•œ key๊ฐ€ ๋œ๋‹ค๋Š” ๋ง์„ ์„ค๋ช…ํ•˜๊ธฐ์— ์•ž์„œ SWR์— ๋Œ€ํ•ด ์ž‘์€ ์„ค๋ช…์„ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
SWR์€ ๊ธฐ๋ณธ์ ์œผ๋กœ useSWR()์„ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค API๋ฅผ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ณ  ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ๋ฐ–์— ๋‚˜๊ฐ”๋‹ค๊ฐ€ ํฌ์ปค์Šค ๋์„ ๊ฒฝ์šฐ๋‚˜ ์ง€์ •๋œ ์‹œ๊ฐ„ ๋“ฑ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์ž๋™์ ์œผ๋กœ API๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

  • ์–ด๋–ค ๋Š๋‚Œ์ธ์ง€ ์ง์ ‘ ํ™•์ธํ•ด ๋ณด๋ ค๋ฉด ์œ„ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•œ ํ›„ ์‹คํ–‰ํ•˜๊ณ  ๊ฐœ๋ฐœ์ž ํŒจ๋„์˜ ๋„คํŠธ์›Œํฌ๋ฅผ ์—ด์–ด๋†“๊ณ  ๋‹ค๋ฅธ ํƒญ์— ๊ฐ”๋‹ค๊ฐ€ ๋‹ค์‹œ ํฌ์ปค์Šค๋ฅผ ์ฃผ๋Š” ๊ฒฝ์šฐ์— ๋‹ค์‹œ API์š”์ฒญ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ๋ชจ๋“  ํŽ˜์ด์ง€๋งˆ๋‹ค useSWR()์„ ์ด์šฉํ•ด์„œ ๊ฐ™์€ url์— ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค๊ณ  ํ•˜๋”๋ผ๊ณ  SWR์—์„œ url์„ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹ฑํ•ด๋‘๊ธฐ ๋•Œ๋ฌธ์— ํŽ˜์ด์ง€์— ์ž…์žฅํ•  ๋•Œ๋งˆ๋‹ค ํ•ญ์ƒ ์š”์ฒญ์„ ๋ณด๋‚ด์ง€ ์•Š๊ณ  ๊ธฐ์กด์— ์š”์ฒญํ–ˆ๋˜ key์ธ์ง€ ํ™•์ธํ•˜๊ณ  ๊ธฐ์กด์— ์š”์ฒญํ–ˆ๋‹ค๋ฉด ์›๋ž˜ ์บ์‹ฑํ–ˆ๋˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ , ์•„๋‹ˆ๋ผ๋ฉด ์ƒˆ๋กœ์šด key๋กœ url์„ ๋“ฑ๋กํ•˜๊ณ  ์บ์‹ฑํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์œ„ ์„ค๋ช…์ด url์ด ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹ฑํ•˜๊ธฐ ์œ„ํ•œ ์œ ์ผํ•œ key๊ฐ€ ๋œ๋‹ค๊ณ  ํ–ˆ๋˜ ๋ง์˜ ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

โš™๏ธ ์ „์—ญ ์„ค์ • ๋ฐฉ๋ฒ•

fetcher๋‚˜ option๋“ค์„ ์ „์—ญ์ ์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
์‚ฌ์šฉํ•  ๋•Œ๋Š” ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•ด์„œ ๋…๋ฆฝ์ ์œผ๋กœ ๋‹ค๋ฅธ fetcher๋‚˜ option์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { SWRConfig } from "swr";

const fetcher = (url: string) => fetch(url).then((res) => res.json());

const App = () => {
  return (
    <SWRConfig
      value={{
        fetcher,
      }}
    >
      // ์ดํ›„ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋“ค์—์„œ SWR์„ ์‚ฌ์šฉํ•˜๋ฉด ์ „์—ญ์ ์œผ๋กœ ์ง€์ •ํ•œ ์„ธํŒ…๊ฐ’์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.
      <Component />
    </SWRConfig>
  )
}

const Component = () => {
  // ์ „์—ญ์ ์œผ๋กœ fetcher๋ฅผ ์ง€์ •ํ–ˆ์œผ๋ฏ€๋กœ ์ƒ๋žต์ด ๊ฐ€๋Šฅํ•˜๊ณ , ํ•„์š”์— ์˜ํ•ด์„œ ๋‹ค๋ฅธ fetcher๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  const { data, error } = useSWR<UserResponse>("https://jsonplaceholder.typicode.com/users/1");
  
  if(error) return <h3>Failed to load<h3>;
  if(!data && !error) return <h3>Loading<h3>;
  
  return (
    <section>
      <div>{data.name}</div>
      <div>{data.email}</div>
    </section>
  )
}

๐Ÿ‘‰ useSWR() ์‚ฌ์šฉ๋ฒ•

const { data, error, isValidating, mutate } = useSWR(key, fetcher, options)

/**
* data: fetcher๋ฅผ ์‹คํ–‰ํ•œ ์„ฑ๊ณต์ ์ธ ๊ฒฐ๊ณผ
* error: fetcher์—์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜
* isValidating: ์š”์ฒญ์ด๋‚˜ ๊ฐฑ์‹  ๋กœ๋”ฉ์˜ ์—ฌ๋ถ€
* mutate: ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฎคํ…Œ์ดํŠธํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜ ( ๋ฎคํ…Œ์ดํŠธ์— ๋Œ€ํ•ด์„œ๋Š” ๋’ค์—์„œ ์„ค๋ช… )
* key: url์ด์ž ์บ์‹ฑ์„ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ์œ ์ผํ•œ key
* fetcher: ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ Promiseํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ ( fetch, axios )
* options: ๋„ˆ๋ฌด ๋งŽ๊ณ  ํ•„์ž๋„ ์‚ฌ์šฉ๊ฒฝํ—˜์ด ๋งŽ์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ณต์‹๋ฌธ์„œ ์ฐธ๊ณ  ๋ฐ”๋žŒ
*/

๐Ÿ‘€ ์ž๋™ ๊ฐฑ์‹  ๋น„ํ™œ์„ฑํ™”

import useSWR from "swr";
import useSWRImmutable from 'swr/immutable'

// ์•„๋ž˜ ๋‘๊ฐœ๋Š” ์•ˆ๋ฒฝํ•˜๊ฒŒ ๊ฐ™๊ฒŒ ๋™์ž‘ํ•จ
useSWR(key, fetcher, {
  revalidateIfStale: false,
  revalidateOnFocus: false,
  revalidateOnReconnect: false
});
useSWRImmutable(key, fetcher)

โ›… ์กฐ๊ฑด๋ถ€ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

import useSWR from "swr";

useSWR(router.query.id ? `/api/users/${router.query.id}` : null, fetcher);
useSWR(() => router.query.id ? `/api/users/${router.query.id}` : null, fetcher);
// ์œ„ ๋‘๊ฐ€์ง€ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ๊ฐ€๋Šฅ
/*
* key๋กœ ๋ฌธ์ž์—ด์„ ๋„˜๊ธธ๊ฒฝ์šฐ ๋ฐ”๋กœ key๋กœ ์‚ฌ์šฉํ•˜๊ณ , null์„ ๋„˜๊ธฐ๋ฉด ์š”์ฒญ์„ ํ•˜์ง€ ์•Š์Œ
* key๋กœ ํ•จ์ˆ˜๋ฅผ ๋„˜๊ธธ๊ฒฝ์šฐ ๋ฐ˜ํ™˜๊ฐ’์„ key๋กœ ์‚ฌ์šฉํ•˜๋ฉฐ, falsy์ธ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์š”์ฒญํ•˜์ง€ ์•Š์Œ
* ๋‹จ, ๋ฌธ์ž์—ด์„ ๋„˜๊ธธ ๋•Œ ์ •์˜๋˜์ง€ ์•Š์€ ๊ฐ’์„ ๋„˜๊ธฐ๋ฉด ์˜ค๋ฅ˜ ๋ฐœ์ƒ
* ์˜ˆ๋ฅผ ๋“ค๋ฉด router.query.id ๊ฐ’์€ ์ฆ‰์‹œ ๊ฐ€์ ธ์™€์ง€์ง€ ์•Š์œผ๋ฏ€๋กœ undefined์ธ ๊ฐ’์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Œ
* undefined๋ฅผ ๋ฐ”๋กœ ์‚ฌ์šฉํ•ด์„œ ์š”์ฒญํ•˜๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ
*/

0๊ฐœ์˜ ๋Œ“๊ธ€