프론트엔드 외부 라이브러리 의존성 낮추기

2023. 7. 31. 14:08· 테크/프론트엔드
목차
  1. Axios 의존성 낮추기
  2. React-Query 의존성 낮추기
  3. localStorage Web API 의존성 낮추기

프론트엔드 개발을 할 때 우리는 많은 라이브러리를 사용하게 됩니다.

저 같은 경우는 요즘 Axios와 React-Query는 거의 항상 사용하는 것 같아요. React는 기본..!

그러다 최근 이런 생각이 들었습니다.

"이런 라이브러리들의 새 버전을 프로젝트에 적용하게 되면 어떻게 될까?"

특수한 경우에는 해당 라이브러리에 의존하는 많은 부분의 코드를 변경해야 할 수도 있지 않을까요?

 

물론, 외부 요소에 하나도 의존을 하지 않고 애플리케이션을 만들 수는 없습니다.

예를 들어 브라우저에서 제공하는 기능을 이용해야 한다는 사실은 무시할 수 없으니까요.

하지만 외부 요소에 직접적으로 의존하는 코드를 최소화하고, 전체적인 제어권을 우리의 애플리케이션 안으로 가져올 수는 있습니다.

Axios, React-Query 라이브러리와 localStorage Web API를 예시로 살펴봅시다. (제가 실제 프로젝트에서 사용한 예시들입니다)

 

Axios 의존성 낮추기


먼저 Axios 이용에서 최종적으로 어떤 기능이 필요한지 추상적으로 정의해봅시다.

  • HTTP Get 요청
  • HTTP Post 요청
  • 요청 시 헤더 내 인증 토큰 삽입
  • 응답 시 "response success!" 출력

그리고 Axios를 이용하여 정의한 기능들을 구현한 인터페이스를 생성해봅시다.

import Axios, { AxiosRequestConfig } from 'axios';

export default class HttpClient {
  private axios;

  private readonly BASE_URL = 'your server base url';
  
  private readonly AUTH_TOKEN = 'your auth token';

  constructor() {
    this.axios = Axios.create({ baseURL: this.BASE_URL });
    this.setRequestInterception();
    this.setResponseInterception();
  }

  protected async get<Response = unknown>(url: string, config?: AxiosRequestConfig) {
    const res = await this.axios.get<Response>(url, config);
    return res.data;
  }

  protected async post<Response = unknown, Request = any>(url: string, body?: Request, config?: AxiosRequestConfig) {
    const res = await this.axios.post<Response>(url, body, config);
    return res.data;
  }
  
  private setRequestInterception() {
  	this.axios.interceptors.request.use(config => {
      config.headers.Authorization = this.AUTH_TOKEN;
      return config;
    });
  }

  private setResponseInterception() {
    this.axios.interceptors.response.use(value => {
      console.info('response success!');
      return value;
    });
  }
}

 

이제 생성한 위 HttpClient 클래스를 이용하여 모든 HTTP 요청 및 응답을 관리하고, 각 모듈에서는 Axios를 직접적으로 호출하지 않음으로써 Axios 라이브러리에 대한 의존성을 줄일 수 있습니다.

만약 Axios 관련 변경이 발생하더라도 HttpClient 클래스 수정만 수행하면 되겠죠.

HttpClient 클래스 내 get, post 메서드의 인자의 일부 타입으로 Axios에서 제공하는 AxiosRequestConfig 타입을 사용하고 있기 때문에, 여전히 다른 모듈에서 Axios에 의존하는 경향이 조금은 있어보이긴 하네요..

 

React-Query 의존성 낮추기


이번엔 제가 실제 프로젝트에서 React-Query 라이브러리 의존성을 낮춘 방법을 소개하겠습니다.

useQuery, useMutation, useInfiniteQuery Hook 및 fetchQuery 메서드를 커스텀하여 정의했지만, 이 중 useQuery Hook 하나만 살펴보겠습니다.

 

먼저 커스텀할 useQuery Hook의 인자 타입을 정의합니다.

import { QueryKey, UseQueryOptions } from '@tanstack/react-query';
import ExceptionBase from '@/lib/HttpErrorException';

export interface Query<TQueryFnData> {
  queryKey: QueryKey;
  queryFn: () => TQueryFnData | Promise<TQueryFnData>;
  options?: UseQueryOptions<TQueryFnData, ExceptionBase>;
}

위에서 살펴본 Axios의 예시와 같이, React-Query 라이브러리에서 제공하는 QueryKey, UseQueryOptions 타입을 사용하고 있기에 다른 모듈들에서 React-Query에 대한 의존성이 발생할 여지가 있습니다.

이와 같이 외부 라이브러리의 타입을 그대로 사용하는 것에 대한 조치는 더 고민해봐야겠어요..🤔

 

이제 위에서 생성한 타입을 이용하여 useQuery Hook을 재정의합니다.

import { useQuery as useQueryOrigin } from '@tanstack/react-query';
import ExceptionBase from '@/lib/HttpErrorException';
import { Query } from '../types/query';

const useQuery = <TQueryFnData>({
  queryKey,
  queryFn,
  options,
}: Query<TQueryFnData>) => {
  const result = useQueryOrigin<TQueryFnData, ExceptionBase>({
    queryKey,
    queryFn,
    ...options,
  });

  return result;
};

export default useQuery;

이로써 React-Query의 useQuery Hook에 대한 의존성을 조금이나마 줄였습니다.

새로 정의한 useQuery Hook 내 공통 로직을 추가함으로써 중복 코드를 줄일 수 있는 이점도 있습니다.

저는 React-Query의 useMutation Hook을 이와 같이 재정의하고, 내부에 동일한 API 요청을 1초에 한 번만 실행하는 공통 로직을 추가하여 버튼 연타시 발생하는 문제를 해결하기도 했습니다.

 

localStorage Web API 의존성 낮추기


window.localStorage 이용에서 최종적으로 어떤 기능이 필요한지 추상적으로 정의해봅시다.

  • 특정 키에 저장된 데이터 가져오기 - get
  • 특정 키에 데이터 저장하기 - set
  • 특정 키의 데이터 삭제하기 - remove

이제 정의한 기능들을 구현한 인터페이스를 생성해봅시다.

export default class LocalStorage<Data = unknown> {
  private key;

  constructor(key: string) {
    this.key = key;
  }

  get() {
    const data = window.localStorage.getItem(this.key);

    if (data === null) {
      return data;
    }

    return JSON.parse(data) as Data;
  }

  set(data: Data) {
    window.localStorage.setItem(this.key, JSON.stringify(data));
  }

  remove() {
    window.localStorage.removeItem(this.key);
  }
}

 

마찬가지로 별도의 localStorage 인터페이스를 생성함으로써 window.localStorage에 대한 의존성을 줄일 수 있습니다. 변경에 대한 대응은 생성한 LocalStorage 클래스에서만 수행하면 될테니까요.

이 뿐만 아니라 클래스를 통해 키(key)에 대한 은닉화도 할 수 있겠네요.

 

위 LocalStorage 클래스는 아래와 같이 활용할 수 있습니다.

import type { Book } from 'book';
import LocalStorage from '../../lib/LocalStorage';

class NewBookRepository extends LocalStorage<Book> {
  constructor() {
    super('SEJULBOOK_NEWBOOK');
  }
}

export default NewBookRepository;

 

이렇게 하면 로컬 스토리지에 대한 키가 분산되지 않고, 키를 몰라도 특정 데이터에 접근할 수 있습니다.

또, 만약 위 NewBookRepository 클래스 내 프로퍼티 또는 메서드를 추가하여 더 확장성 있게 사용할 수도 있겠네요.

 

.

.

.

 

우리의 프로젝트에는 정말 많은 라이브러리와 Web API가 사용됩니다. 이 모든 것들에 대해 위 예시들처럼 별도의 인터페이스를 구현할 수는 없겠죠.

따라서 여러 모듈들에서 빈번히 직접 접근하여 사용하는 것들을 선정하여 의존성을 줄이는 것이 좋아보입니다.

그리고 꼭 의존성을 줄이기 위해서가 아니더라도 확장성 및 재사용성을 높이기 위한 목적으로도 좋은 방법이 될 수 있습니다.

저작자표시 (새창열림)
  1. Axios 의존성 낮추기
  2. React-Query 의존성 낮추기
  3. localStorage Web API 의존성 낮추기
'테크/프론트엔드' 카테고리의 다른 글
  • 서비스워커를 사용하여 S3 스토리지 최적화하기 (그리고 오버엔지니어링에 대해)
  • 프론트엔드 성능 개선기 - 번들 최적화
동쪽별
동쪽별
You'll Never Walk Alone.
동쪽별
개발자 동쪽별
동쪽별
전체
오늘
어제
  • ALL (40)
    • 테크 (30)
      • 자바스크립트 (13)
      • 리액트 (2)
      • Next.js (2)
      • 프론트엔드 (3)
      • 알고리즘 (5)
      • 네트워크 (4)
      • 에러 (1)
    • 회고 (7)
    • 서평 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • Github

최근 댓글

hELLO · Designed By 정상우.v4.2.2
동쪽별
프론트엔드 외부 라이브러리 의존성 낮추기
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.