ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Nextjs ์—์„œ fetch ์ปค์Šคํ…€ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ธฐ(feat. ์ด์ค‘ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜)
    ์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ 2024. 2. 4. 19:50

    ์ง€๋‚œ๋ฒˆ์— https://minju-k.tistory.com/15 ์—์„œ Next.js ๋Š” ๋‹ค์–‘ํ•œ ์บ์‹ฑ ์˜ต์…˜์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” fetch๋ฅผ ์ด์šฉํ•˜๊ธธ ๊ถŒ์žฅํ•˜๋Š” ๊ฒƒ์„ ์•Œ์•„๋ณด์•˜๋‹ค.

     

    ์ด ๊ธ€์—์„œ๋Š” ๊ทธ๋ž˜์„œ ์–ด๋–ป๊ฒŒ ํ”„๋กœ์ ํŠธ์— fetch๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ๋„ axios๋ฅผ ์“ธ ๋•Œ์ฒ˜๋Ÿผ์˜ ์ด์ ์„ ๋ˆ„๋ฆฌ๋„๋ก ํ–ˆ๋Š”์ง€ ๊ธ€์„ ์จ๋ณด๊ธฐ๋กœ ํ•œ๋‹ค. ๋งŒ๋“ค ๋•Œ์—๋Š” ์•„๋ž˜์— ๋ ˆํผ๋Ÿฐ์Šค๋กœ ๊ฑธ์–ด๋†“์€ return-fetch ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์˜€๋‹ค.

     

    axios๋Š” fetch์— ๋ฐ˜ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

     

    - ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ„๋„ serialize, deserialize ํ•  ํ•„์š”๊ฐ€ ์—†์ด ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    - baseUrl์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
    - default header๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
    - request, response interceptor๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    ๋‚ด๊ฐ€ ๋งก์€ ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” baseUrl์„ ์ด 4๊ฐœ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—,

    axios๋ฅผ ์‚ฌ์šฉํ• ๋•Œ ๊ธฐ๋ณธ ์˜ต์…˜๋“ค์„ ์ง€์ •ํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐœ์˜ axiosClient๋ฅผ ๋งŒ๋“ค๋“ฏ์ด, fetch๋„ ๊ธฐ๋ณธ ์˜ต์…˜์„ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•œ ํ˜ธ์ถœ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ํ™œ์šฉํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.

     

    ๋”ฐ๋ผ์„œ ์šฐ์„  DefaultOption์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค. ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ๋Š” axiosClient๋ฅผ ๋งŒ๋“ค๋•Œ์™€ ๊ฐ™๋‹ค.

    import Cookies from 'js-cookie';
    
    interface IRequestOptions {
      method?: string;
      headers?: Headers;
      mode?: string;
      cache?: string;
      body?: Record<string, any> | string;
    }
    
    interface IInterceptors {
      request: (args: IRequestOptions) => void;
    }
    
    interface IDefaultOptions {
      baseURL: string | undefined;
      headers: {
        'Content-type': string;
        'X-SNAPS-CHANNEL': string;
      };
      mode: string;
      interceptors: IInterceptors;
    }
    
    const defaultOptions: IDefaultOptions = {
      baseURL: process.env.NEXT_PUBLIC_API_URL,
      headers: {
        'Content-type': 'application/json; charset=UTF-8',
        'X-SNAPS-CHANNEL': 'DA_WEB',
      },
      mode: 'cors',
      interceptors: {
        request: (args: IRequestOptions) => {
          const token = Cookies.get('OH_PRINT_ME_GROUND_USER_TOKEN');
    
          if (!token) return;
    
          if (token) {
            if (!args.headers) {
              args.headers = new Headers();
            }
            args.headers.set('X-SNAPS-TOKEN', token);
          }
        },
      },
    };
    

     

    ๊ทธ๋ฆฌ๊ณ ๋Š” DefaultOption์„ ๊ธฐ๋ณธ์œผ๋กœ ๋ฐ›๊ณ , url๊ณผ option์„ ๋ฐ›์•„ API๋ฅผ ํ˜ธ์ถœํ•œ ํ›„ ์‘๋‹ต์„ ๋ฆฌํ„ดํ•ด์ฃผ๋Š” fetcherํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.

     

    defaultOption๋งŒ ๋‹ค๋ฅด๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋ฉด, baseUrl์ด๋‚˜ ๊ธฐ๋ณธ์ ์ธ interceptor ์‚ฌ์šฉ ์˜ต์…˜๋“ค์ด ๋‹ฌ๋ผ์ง„๋‹ค ํ•ด๋„ ๊ณ„์† ์ด fetcher ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

     

    ์ด ๋•Œ ์ด์ค‘ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ, ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด fetcher๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค defaultOption์„ ์ธ์ž๋กœ ๋ณด๋‚ด์ฃผ์ง€ ์•Š์•„๋„ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๋ฅผ ํ™œ์šฉํ•œ ๋‚ด๋ถ€ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    const fetcher =
      (defaultOptions: IDefaultOptions) =>
      async (url: string, options: IRequestOptions = {}) => {
        const requestOptions: IRequestOptions = {
          method: options.method || 'GET',
          headers: new Headers(defaultOptions.headers),
          mode: defaultOptions.mode,
          ...options,
        };
    
        defaultOptions.interceptors.request(requestOptions);
    
        const fullURL = defaultOptions.baseURL + url;
    
        if (requestOptions.method === 'POST' && requestOptions.body !== undefined) {
          requestOptions.body = JSON.stringify(requestOptions.body);
        }
    
        try {
          const response = await fetch(fullURL, requestOptions);
    
          if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
          }
    
          const data = await response.json();
          return data;
        } catch (error) {
          console.error(error);
          throw error;
        }
      };

     

    ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜

    ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ๋” ํ™•์‹คํ•˜๊ฒŒ ์ดํ•ดํ•˜๊ณ  ๊ฐ€์ž.

    const add = a => b => {
     return a + b;
    }
    
    const add = a + b => {
      return a + b;
    }

     

    ์ด ๋‘ ํ•จ์ˆ˜์˜ ์ฐจ์ด์ ์€, ์ฒซ ๋ฒˆ ์งธ๋Š” a๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ์™ธ๋ถ€ํ•จ์ˆ˜๊ฐ€ b๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๋Š” ํ˜•ํƒœ์ด๊ณ , ๋‘ ๋ฒˆ์งธ๋Š” a,b๋ฅผ ๋™์‹œ์— ์ธ์ž๋กœ ๋ฐ›์•„์„œ ๊ทธ ํ•ฉ๊ณ„๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ํ˜•ํƒœ๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

     

    ์ฒซ ๋ฒˆ์งธ ํ•จ์ˆ˜๋ฅผ ์šฐ๋ฆฌ์—๊ฒŒ ์ต์ˆ™ํ•œ ํ˜•ํƒœ๋กœ ํ’€์–ด์„œ ์ž‘์„ฑํ•ด ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    function(a){
      function(b){
        return a + b;
      }
    }
    
    function(a,b){
      return a + b;
    }

     

     

    ์ด๋ ‡๊ฒŒ ์ด์ค‘ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์˜ ์žฅ์ ์€ a๋ฅผ ๋งค๋ฒˆ ์ธ์ž๋กœ ๋„˜๊ฒจ์ฃผ์ง€ ์•Š์•„๋„, ์ด a๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ํ™œ์šฉํ•œ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์•„๋ž˜๋Š” ์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์–ด๋–ค ๊ฐ’์„ ๋„ฃ๋”๋ผ๋„ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ธ์ž๋กœ ๋„˜๊ฒจ๋†“์€ 2๋ฅผ ๋”ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค. 

    const add = a => b => a + b;
    
    const add2 = add(2);
    
    console.log(add2) // b => 2 + b;
    
    add2(3); // 5
    add2(4); // 6

     

     

    ๋”ฐ๋ผ์„œ fetcher๋„ defaultOption์„ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์šฉํ•œ ๋‚ด๋ถ€ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋งŒ๋“  ๊ฒƒ์ด๋‹ค.
    ์ตœ์ข…์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ customFetcher ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ , ํ˜ธ์ถœ ์‹œ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋„๋ก ํ–ˆ๋‹ค.

    export const customFetcher = fetcher(defaultOptions);
    // ์œ„์˜ add2์™€ ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“  ๊ฒƒ์ด๋‹ค!!
    
    // method ์˜ต์…˜์„ ๋ณ„๋„๋กœ ๋„˜๊ธฐ์ง€ ์•Š์•˜์„ ๋•Œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ GET์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋˜์–ด ์žˆ์œผ๋‹ˆ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ณตํ†ต SWRConfig๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.
    export default function SWRConfigContext({ children }: Props) {
      return (
        <SWRConfig
          value={{
            refreshInterval: 3000,
            fetcher: (url: string) => customFetcher(url),
          }}
        >
          {children}
        </SWRConfig>
      );
    }
    
    // POST๋‚˜ cache option ์‚ฌ์šฉ์‹œ
      const data = await customFetcher(url, {
        method: 'POST',
        body: { loginId, password },
        method : 'no-store'
      });

     

    ์ด์ œ axios์—์„œ axiosClient๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์‚ฌ์šฉํ•˜๋“ฏ์ด customFetcher๋ฅผ ์‚ฌ์šฉํ•ด์„œ๋„ axios์ฒ˜๋Ÿผ ๊ฐ„๋‹จํžˆ APIํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.


    ์ด์ค‘ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์—ฌ๋Ÿฌ๋ฒˆ ์žฌํ™œ์šฉ ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ณผ์ •์ด ์ฐธ ์žฌ๋ฏธ์žˆ์—ˆ๊ณ , ์•ž์œผ๋กœ๋„ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๊ธฐ๋ณธ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•  ๋•Œ์—๋Š” ์ด๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

    ๋Œ“๊ธ€

Designed by Tistory.