[프로젝트] Vue Query를 통해 불필요한 api 요청 없애기!

ljk4268·2023년 12월 3일
2

버퍼링이 너무 길어요! 🥲

지금 하고 있는 프로젝트에 차트 페이지가 하나 있다.
셀렉트 박스 옵션에 따라 서버에서 데이터를 받아와 그래프를 그려주는 방식인데
서버에서 데이터를 받아오는 시간이 너무 길어 그래프 조회 시 오래 걸린다는 의견이 나왔다.

실제로 데이터 받아오는 시간이 얼마나 걸리나 확인해보니 4-5초가량 소요되는걸로 확인 되었다.

❓ 해결방법은 뭐가 있을까!

백엔드 분과 해당 이슈에 대해 이야기 나누어봤고,
지금 1개의 API에서 여러 데이터를 받아오느라 응답시간이 오래 걸리고 있으니까
1개의 API를 여러 개로 나누는 세분화 작업을 하자고 하셨다.
나도 그 말에 동의했고, 백에서 api를 세분화하면 적용하면 되겠다 싶었다.

그러다 문득 next.js를 공부하면서 알게된 react-query가 생각났다.

API세분화작업을 하더라도 사용자가 셀렉트박스의 옵션을 변경할때마다 네트워크 요청이 될거고, 그에따른 응답받는 시간은 매번 생긴다.
vue-query가 있다면 데이터 캐싱을 통해 네트워크 요청을 하지 않아도 될텐데!

어디 한 번 적용해볼까? 😏😏😏

라는 가벼운 마음으로 시작한 고된 작업이 시작되었다^^...


✅ vue-query 적용하기!

vue-query 공식문서와 유튜브를 통해 찾은 영상을 많이 참고해서 내 프로젝트에 적용했다.

1. vue-query 설치하기

공식문서에 나온대로 vue-query를 설치하고, main.js파일에 플러그인으로 등록해서 전역적으로 기능을 추가해줬다.

npm install vue-query
// src > main.js

import { VueQueryPlugin } from "vue-query";

app.use(VueQueryPlugin);

2. setup()에서 useQuery사용하기

실제 프로젝트에 사용하는 코드를 담을 수 없어 일부 코드가 생략되어 있다.

완성코드

<script>
import { useQuery } from 'vue-query';

const testFetcher = async (a, b, c) => {
  const res = await axios({
    url: `api/${a}/${b}/${c}`,
    method: 'get',
  });
  return res.data;
};

export default {
  setup(props){
    
    watch(
      () => props,
      () => {
        queryA.value = props.a;
        queryB.value = props.b;
      },
      { deep: true }
    );
    
    
    const queryA = ref(props.a);
    const queryB = ref(props.b);
    const queryC = ref('');

    const { data } = useQuery({
      queryKey: ['test', queryA, queryB, queryC],
      queryFn: () => testFetcher(queryA, queryB, queryC),
      keepPreviousData: true,
      staleTime: 5 * 60 * 1000,
    });
    
    watch(() => data.value, (newData) => {
      // newData로 실행할 로직 
    })
  }
}
  
</script>

적용하며 어려웠던 점

1. ❓props의 변경을 인지하지 못함.

나의 경우 셀렉트박스로 변경되는 데이터가 총 3가지가 있다.
2개는 props로 받아오고, (= 위의 코드로 보면 a,b에 해당)
1개는 해당 파일 내에서 변경이 이루어진다. ( = 위의 코드로 보면 c에 해당 )

props로 받아오는 데이터를 편하게 a,b 라고 말하자면
a,b가 변경될때마다 API 호출을 통해 데이터를 새로 받아와야 한다.

queryKey: ['test', props.a, props.b, queryC],

처음에는 위 코드처럼 queryKey로 지정해서 데이터가 변경될 때마다 testFetcher 실행 해달라고 요청해놨는데
애들이 요청을 하지 않더라... 🥹🥹🥹 ( 이러지마 왜그래..? )

레퍼런스가 많이 없어서 chatgpt한테 물어보니

💡queryKey의 값이 변경될 때마다 해당 쿼리를 다시 실행하게 하려면 반응형 상태여야 한다고 한다.

그래서 받아온 props를 ref를 사용하여 반응형 상태로 만들어줬다.

const queryA = ref(props.a);
const queryB = ref(props.b);
const queryC = ref('');
const { data } = useQuery({
  queryKey: ['test', queryA, queryB, queryC],
  queryFn: () => testFetcher(queryA, queryB, queryC),
  keepPreviousData: true,
  staleTime: 5 * 60 * 1000,
});

✔️ props의 변경을 인지하지 못하는 점 반응형 상태 만들어서 해결!

2. ❓데이터는 받아오는데, 네트워크 요청은 계속된다..!!

내 기대는 vue-query를 사용하면 한 번 요청했던 데이터를 반복 요청했을 때
네트워크 요청을 하지 않고 캐싱 된 데이터를 가져오는 것이었다.
근데 같은 데이터를 요청해도 계속 네트워크 요청이 들어가더라.. 모야 모가 문제야!!

💡 staleTime

query를 사용할 때 중요한 개념 중에 하나인 staleTime이 있다.
데이터가 신선한 상태인지, 아닌지 판단해 주는 값인데, 기본값은 0!
staleTime이 0인 경우 데이터가 신선하지 않다고 생각하고 네트워크 요청을 통해 데이터를 다시 가지고 온다.

아... 나 이거 react-query 강의 들을 때 분명 들었던 개념인데 홀라당 까먹고 있었다 🥲🥲🥲

이거 때문에 잘 적용된 vue-query가 적용 안된 줄 알고 몇 시간을 헤맸다 허허허 😂😂😂

staleTime: 5 * 60 * 1000,

나의 경우 staleTime을 5분으로 설정했다.
cacheTime이라고 해서 캐싱 된 데이터가 삭제될 때까지의 시간이 있는데
vue-query의 cacheTime 디폴트 값이 5분이다.
디폴트 값에 맞춰 일단 5분으로 설정을 해두었는데,

vue-query 적용기 시작은 서버에서 데이터를 받아오는 시간이 너무 길어 그래프 조회 시 오래 걸린다는 의견때문이였고,
우선 백엔드 분과의 소통을 통해 API 세분화를 하자고 얘기가 나온 상태였다.
확실하게는 PM님과 프로젝트 회의를 거쳐 어떻게 할지 결정해야 하는 거였는데
프론트 쪽에서 캐싱을 통해 그래프 그리는 속도를 빠르게 할 수 있다.라는 제안을 할 수 있을 거 같아 test 삼아 적용해본 거였다.

실제로 프로젝트에 vue-query를 도입할지 말지는 회의를 통해 결정되어야 했고,
만약 vue-query를 도입한다면 그때 staleTiem과 cacheT ime을 회의를 통해 결정하기 위해 우선 default로 적용해두었다.

3. ❓data가 바뀔때마다 그래프가 새로 그려져야 하는데... ?

vue-query를 도입하기 전에는 셀렉트 옵션이 변경될 때마다 API 호출을 통해 데이터를 새로 가져와서 그래프가 매번 새롭게 그려졌었는데,
vue-query를 도입하니 새로 가져온 데이터로 그래프를 그리게 연결할 수 있는 일종의 트리거..가 없었다. 아니 정확히는 그 방법을 모르겠더라.

const { data } = useQuery({
  queryKey: ['test', queryA, queryB, queryC],
  queryFn: () => testFetcher(queryA, queryB, queryC),
  keepPreviousData: true,
  staleTime: 5 * 60 * 1000,
  onSucess: (newData) => {
  	// 바뀐 데이터로 그래프 그리는 작업
  }
});

그래서 처음에는 onSuccess()라는 메소드를 통해 query호출이 성공적이라면 그래프에 데이터를 직업넣는 작업을 하려고 했는데,
데이터가 캐싱된 경우 onSuccess()가 실행되지 않았다.

💡watch를 사용하자

Vue Devtools로 확인해 보면 query로 가져온 data가 반응형 상태가 된 것을 확인할 수 있다.
watch를 통해 data가 변경되면 그래프 그리는 작업을 실행하면 될 거 같았고, 적용하니 원하는대로 나왔다!
단, query가 data를 ref 형태로 리턴하니 watch에 사용할때 data.value로 써줘야한다.

watch(() => data.value, (newData) => {
  // newData로 실행할 로직 
})

✅ 적용 됐는지 확인하기!


이미지의 10이라는 API가 셀렉트박스 옵션이 변경될때 실행되는 요청이다.

  1. 10이라는 API를 한 번 요청하고,
  2. 옵션을 다르게해서 11이라는 API를 요청을 한 뒤
  3. 다시 10이라는 API를 요청하도록 했는데~~
  4. 네트워크 요청을 하지 않고 캐싱되어 있는 데이터로 그래프를 그려주고 있었다. 그것도 아주 빠.르.게. 히히히히히😁😁😁
    (valuationBubbleChart API전에 요청되어야 하는데 아래쪽 보면 요청되지 않은 것을 확인할 수 있다! )

굳이 네트워크요청을 확인하지 않아도
그래프가 데이터를 그리는 속도만 봐도 vue-query가 잘 적용됐구나를 알 수 있었다.

이제 회의때 그래프 그리는 속도 개선할 수 있는 방법으로 vue-query를 제안하고,
API 세분화까지 하면 클라이언트가 불편해했던 버퍼링 이슈를 해결할 수 있을거 같다! ㅎㅅㅎ


profile
적응중

0개의 댓글