React

react-query 쓰다가 this 깨닫기

FE 2022. 6. 20. 16:28

어떻게 보면 저번 FE에서 OOP의 대한 고민 포스트의 대한 연장선일 것 같네요!

 

API를 클래스로 바꾸어 react-query를 같이 쓰면서 한번 더 깨닫게 된 내용이니까요. 다들 Arrow Function 많이 쓰시나요? function과 Arrow function의 차이점은 저도 직접 경험했다기보다는 어떤 차이점이 있지?라고 찾아보고 이론적으로 접한적이 더 많은 것 같습니다.

 

간단하게 function VS arrow function의 차이점을 짚고 넘어가봅시다.

  • 일반 함수의 this - 함수를 호출할 때 어떻게 호출되었는지에 따라 this에 바인딩 할 객체가 동적으로 결정된다.
  • 화살표 함수의 this - 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되고, 상위 스코프의 this를 가리킨다.

 

원래는 함수가 쓰인 위치에 따라 내부 this값이 변하는데 화살표 함수는 어디서 쓰든간에 내부의 this값을 변화시키지 않습니다.

 

내부의 this값을 변화시키지 않는다는 말이 중요한데 저 this 바인딩 값이 바뀌어서 고생을 했었거든요.

 

// API - testApi.ts
class TestApiService {
  url: string;
  constructor(url: string) {
    this.url = url;
  }

  async getTestApi() {
    console.log(this);
    const result = await $axios.get<GetTestResponse>(`${this.url}/me`);
    return result.data;
  };
}
export const testApiService = new TestApiService("/v1/test");

// react-query - test.ts
export const useGetTestApi = () => {
  return useQuery("test", testApiService.getTestApi);
};

 

최초에 이렇게 코드를 작성했었는데요.

 

이렇게 url이 undefined로 나오는 겁니다. 사실 원인 파악을 바로 하지 못해 삽질도 좀 했던 것 같습니다..ㅎㅎ

 

원인은 위에서 말했던 일반함수와 화살표함수에서 찾을 수 있습니다.

이렇게 작업을 하게 되면 useQuery한테 호출을 위임하게 됩니다. 즉, 위 코드는 useQuery를 갔다오면서 실행 주체가 바뀌기 때문에 this 바인딩이 되서 값이 바뀌는 것이죠. 두 가지 방법을 유추할 수 있었습니다..

 

가장 먼저 떠오른 방법은 화살표 함수였습니다. 함수 선언 시, 정적으로 this 값이 바인딩 되기 때문에 걱정할 필요가 없습니다. 다른 방법으로는 bind 함수를 써서 해결할 수 있겠네요.

https://ko.javascript.info/bind

 

1. 화살표 함수로 해결

// API - testApi.ts

class TestApiService {
  url: string;
  constructor(url: string) {
    this.url = url;
  }

  testApi = async () => {
    console.log(this);
    const result = await $axios.get<GetTestResponse>(`${this.url}/me`);
    return result.data;
  };
}
export const testApiService = new TestApiService("/v1/test");

// react-query - test.ts

export const useGetTestApi = () => {
  return useQuery("test", testApiService.getTestApi);
};

2. bind로 해결

// API - testApi.ts

class TestApiService {
  url: string;
  constructor(url: string) {
    this.url = url;
  }

  async getTestApi() {
    console.log(this);
    const result = await $axios.get<GetTestResponse>(`${this.url}/me`);
    return result.data;
  };
}
export const testApiService = new TestApiService("/v1/test");

// react-query - test.ts

export const useGetMyXquares = () => {
  return useQuery("test", testApiService.getTestApi.bind(testApiService);
};

 

이렇게 해서 문제 해결을 할 수 있었고 저는 화살표 함수로 해결했습니다.

 

이미 이론적으로는 알고 있던 내용인데, 삽질을 했던 시간이 순간적으로 좀 괴로웠습니다.

 

스스로를 좀 피드백 해보자면 여기서 아!!!!!!!, 아~~~~~의 중요성을 좀 깨달았던 것 같습니다. 아!!!는 어떤 문제를 보고 바로 떠올랐다면 아~~~는 질문이나 검색을 통해서 누군가의 설명이나 아이디어를 듣고 깊게 알고 있던 지식을 다시 깨달은 느낌이랄까요..?

 

예를 들면 어떠한 문제를 겪으면서 '이럴 때 바로 이거 쓰면 되겠다, 이거인 것 같은데?'인 경우와 이럴 때 '어떻게 해결하지? 왜이러지?'는 큰 차이라고 생각하거든요. 어떠한 코드를 보고, 누가 썼던 코드를 보면서 아 그거 이거 안되지, 이런거 막아주지 하는 것들은 결국 이론적으로 알고 있었지만 실전에 적용하지 못했던 것이죠..중요한 점은 이론적으로 이해하고 넘어간 것과 직접 코드를 작성하며 이해하고 넘어간 것의 차이였던 것 같습니다.

 

앞으로는 왜 이렇게 되지?(Why)와 실습(Experience)으로 깨닫는 연습을 중점적으로 해야겠다고 다짐하게 만든 문제였던 것 같습니다.