지금 주인장은 Nest.js 공부 중 ···

프론트엔드

프론트엔드 개발에 관련된 내용을 포스팅합니다.
Vue에서 Tanstack Query 사용 시에 Persistent 하게 유지하기
글을 시작하며 Tanstack Query는 기본적으로 인메모리 캐시를 사용하기 때문에, 브라우저 새로고침 시에 자바스크립트 런타임이 초기화되면서 모든 캐시 처리가 사라진다. staleTime이 남아있더라도 캐시 자체가 메모리에서 사라지기 때문에 다시 패칭되는 현상이 발생한다. Query Cache의 구조 Tanstack Query는 Map<string, Query> 형태로 쿼리 키를 해시화해서 저장을 한다. 이때 각 쿼리는 queryKey 를 기반으로 고유하게 식별된다. 그래서 queryKey 에는 캐싱 개념에서 정말 중요한 유니크한 값이 들어가야한다. 각 Query 들은 아래와 같은 정보들을 포함한다. queryKey : 쿼리 식별자 (배열 형태) state : 현재 쿼리 상태 data : 실제 응답 데이터 dataUpdatedAt : 데이터 업데이트 시각 error : 에러 정보 status : pending|error|success fetchStats : fetching |paused|idle ... observers : 해당 쿼리를 구독 중인 컴포넌트들 gcTime : 가비지 컬렉션 시간 (구 cacheTime) staleTime : 데이터 신선도 기준 시간 캐시 라이프사이클과 메모리 상태 Tanstack Query의 내부 캐시 라이프 사이클 Tanstack Query의 메모리 상태 persistQueryClient로 localStorage에 직렬화하여 저장하기
  • 현우
Vue에서만 확인할 수 있는 Tanstack Query의 독특한 패턴
글을 시작하며 현재 Vue.js 의 Tanstack Query를 API 관련 컴포저블 (React.js로 따지면 커스텀 훅) 형태로 필요한 곳에서 useQuery나 mutation으로 사용하고 있다. 단순 단일 데이터의 조회라면 상관이 없겠지만, 사용자에 의해 유동적으로 값이 바뀌면서 동적인 패칭을 계속해야할 때 리패칭을 해야하는 경우가 많은데 React.js와 달리 Vue.js 프록시 객체를 사용하면 조금 더 리패칭 과정들을 단순화 할 수 있다. 일반적인 Composable 예제 기본 코드 아래는 컴포저블과 컴포넌트 단의 간략한 예제를 담은 코드이다. 위의 코드를 보면 문제점이 하나 발생하는데 사용자는 동적인 데이터를 계속해서 호출하고 싶지만, boardId 는 정적인 상태로 존재하기 때문에 컴포넌트가 리렌더링 되지 않는 이상 단일 데이터를 계속해서 호출하게 되는 문제점이 발생한다. 이 문제를 해결하게 위해서는 boardId 가 변경될 때를 감지하여 리패칭을 해줘야한다. 하지만 내부적으로 캐싱 처리를 진행해야하는 경우에는 리패칭을 하는 것은 캐싱 처리에 아무 의미 없기 때문에 (refetch 메서드는 staleTime 과 상관없이 데이터를 다시 리패치하기 때문이다) 다른 방법을 모색해야한다. refetch를 이용한 변경안 위에서 이야기한 것처럼 boardId 가 변경될 때를 watch 로 감지하여 매번 리패칭을 해줄 수는 있지만, 캐싱 처리 등 부가적인 요소들을 많이 고려해야한다. Proxy 객체를 이용한 변경안 더 좋은 방법은 없을까? Vue.js의 경우 React.js와 달리 Proxy 객체로 구성된 ref 를 queryKey 에 넣어주면, Tanstack Query에서는 Reactive한 쿼리 키(queryKey)를 지원해주기 때문에 내부에서 ref 를 watch하여 자동으로 쿼리를 다시 실행해준다. 위의 코드를 보면 watch 로 boardId 를 감싸주지 않아도 되고, 또 매번 리패칭을 명시적으로 넣어주는 로직 자체가 사라진 것을 확인할 수 있다. 이러한 차이가 발생하는 이유는 초기 값의 스냅샷이나, 아니면 반응형 참조에 따라 다르다는 것을 의미한다. 정적인 문자열로 선언할 경우에는 초기 시점에서의 문자열을 계속해서 가지고 서버에 호출하게 되지만, ref 그 자체를 넘기게 되면 proxy 객체 자체를 넘기는 과정이기 때문에 .value 를 계속 읽으며 Reactive 하게 동작시킬 수 있다는 것이다. 이벤트 자체에서 호출하는 방법을 이용한 변경안 queryClient 의 fetchQuery 를 사용해 직접적으로 필요할 때마다 호출하는 방법이 있다. 다만 fetchQuery 는 useQuery 처럼 ref 와 같이 proxy 객체로 감싸지 않고, 순수 데이터가 들어온다는 것을 주의해야한다. React.js와 Vue.js에서 사용방법이 어떻게 다를까? Vue.js : proxy (전역 Reactivity 시스템 위에 존재) React.js : Virtual DOM + Diffing + setState 기반 수동 업데이트 (명시적 상태 업데이트, VDOM 재구성) 아래는 React.js와 Vue.js의 예제이다. useState 와 ref 를 비교해보면 재밌는 상황이 발생한다. React.js에서는 useState 를 사용하는데 getter 와 setter 형태를 제공해주어 queryKey 에 들어가는 타입은 string 이 된다. Vue.js는 proxy 기반 자동 반응형 전역 시스템을 사용하기 때문에 객체 · 값을 감싸고 객체 프로퍼티 접근을 자동으로 추적해 값이 바뀌면 알아서 재실행 및 렌더링을 시켜준다. Reactive 라는 개념이 Vue.js에서 특화된 개념이기 때문에, Vue.js 에서만 가능한 패턴이기도 하다. 글을 마치며 Vue.js를 처음 공부할 때 React.js에서 작성했던 코드들과 함께 비교해서 학습을 하고 적용을 하다보니, 정말 다방면에서 차이점을 몸소 체감할 수 있고 이로 인해 성장을 할 수 있는 것 같다. 아직 proxy 객체에 대해서 많은 지식을 가지고 있지 않아, 계속해서 학습을 진행해보려고한다.
  • 현우
당장 타입 시스템을 도입해야된다면 @ts-check를 사용해보세요
글을 시작하며 사내 일부 프로젝트에서는 타입스크립트를 사용하고 있지만, 위협 인텔리전스 플랫폼의 서비스는 자바스크립트로 이루어져있다. 자바스크립트에서 점점 프로젝트가 커지면 커질수록 코드 추적이나, 함수의 매개변수가 어떤 것들이 있는지 파악하기 어려워진다는 특징이 있는데 이 때문에 타입 정의에 대한 중요성이 상당히 크게 느껴졌다. 아마 이 포스팅은 기존 자바스크립트의 JSDOC을 활발하게 사용하고 있는 조직이나, 타입스크립트를 점진적으로 도입하고 있는 조직들에게 도움이 될만한 포스팅이라고 생각이 든다. 자바스크립트의 타입 체킹에 대한 중요성이 왜 커지고 있을까? 서비스가 성장하면 성장할수록 코드는 방대해지고, 또 기능이 많아질수록 의존되는 코드 또한 많아지기 마련이다. 이때 한 개발자가 여러 기능의 코드를 모두 기억할 수는 없기 때문에 어떠한 함수가 있다고 가정했을 때, 해당 함수가 어떤 역할과 목적을 가지고 있는지 파악하기 힘들다는 단점이 있다. 코드를 추적하고 추적한 끝에 함수의 파라미터들의 타입과 리턴 등의 여러 요소들을 파악하면 정말 좋겠지만, 의존성이 정말 강한 함수의 경우에는 추적하는데 많은 시간이 소요될 뿐만 아니라, 휴먼 에러로 인해 잘못된 타입을 기재한다거나 잘못 이해한 리턴 값으로 서비스에 장애를 초래할 수 있다. 자바스크립트는 타입에 대한 선언이 정말 자유롭기 때문이다. 대규모 서비스일수록 타입 시스템의 필요성이 정말 중요하다고 생각했고, 휴먼 에러를 줄이고 더 빠르게 타입을 추적하기 위해 중요성이 커지고 있다. 아마 요 근래 프론트엔드 서비스들을 보면 타입스크립트를 도입한 이유 중 주된 이유가 이 이유가 아닐까 싶다. 타입스크립트를 도입하기에는 리소스가 부족하고, 당장 자바스크립트를 이용해야할 때 타입스크립트 세팅을 하기에는 당장 비즈니스 환경에서 무언가 사이드 이펙트가 발생할 수 있고, 리소스가 부족해 타입스크립트를 도입하지 못하는 조직이 있을 수 있다. 물론 초과 근무로 조금 더 시간을 투자해서 프로젝트의 전반적인 부분을 교체하는 것도 좋지만, 업무 내의 시간을 효율적으로 사용하는 것도 정말 중요하다고 생각하기 때문에 그럴 경우에는 점진적으로 타입스크립트를 도입하는 방법 밖에 없다. 타입스크립트를 프로젝트 전반적으로 모두 교체하는 것이 아닌 JSDOC으로 타입에 대한 인터페이스들을 정의하고, 타입스크립트를 도입하는 방법이 있다. 타입스크립트 2.3부터 유형 주석이 존재하는 기존 자바스크립트 코드를 분석할 수 있도록 지원하기 시작했다. 자바스크립트에서 타입스크립트 분석을 실행하기 위해서는 VSCode 에디터 상에서 @ts-check 라는 텍스트가 있는 주석을 파일 제일 시작 부분에 추가만 하면 된다. 그런 다음 파일의 아무 곳에서 타입스크립트의 JSDOC 유형의 주석을 추가하면 된다. 타입스크립트가 내장된 VSCode 에서는 이러한 주석을 자동으로 감지하여 사용자가 기대하는대로 수행할 수 있다. 아쉽게도 웹스톰이나 인텔리제이와 같은 다른 IDE에서는 안되는 것 같은데.. 혹여나 되시는 분들은 댓글에 공유해주세요 : ) 유용하고 자주 사용하는 JSDOC 문법 · @ts-check : 자바스크립트 파일에서도 타입스크립트 타입 체크를 켤 수 있는 지시문이다. · @typedef : 새로운 "타입 이름"을 만드는 선언이다 (타입스크립트의 interface, type 과 같은 타입 선언같은 친구같다) · @property : @typedef 안에 들어가는 각 파라미터들의 "필드 정의" 선언이다. · @type : 특정 변수 · 상수 · 리턴 값에 타입을 붙이는 문법이다. · @param : 함수의 파라미터 타입 지정한다. · @returns : 함수의 리턴 타입을 결정한다.
  • 현우