프론트엔드 데브코스 5기 TIL 73 - react query isPending, Type script와 mapping

김영현·2024년 2월 28일
0

TIL

목록 보기
84/129

React-Query isLoading in v5

내가 지금까지 해오던 react-query의 사용방식이다.

const { isLoading, error, data } = useQuery(...);
                                            
if(isLoading){
	<div> loading... </div>
}

if(error){
	<div> error </div>
}

return(
<div> {data} </div>
)

이렇게 내부에서 처리하거나 ErrorBoundary, Suspense를 이용하여 선언적으로 로딩, 에러를 처리한 뒤, 데이터가 무조건 존재하는 상황에서만 쿼리된 데이터를 사용했다.
=> Type narrowing을 했다.

하지만 v5에서 이렇게 사용하면...

const data = DataType | undefined

이렇게 데이터가 없을수도 있다는 결과를 받게된다.

왜 그런걸까?

깃허브 디스커션 내용에서 완벽하게 설명해주지만, 요약해보자면 아래와 같다.

isPending vs isLoading

일단 useQuery가 리턴하는 값 중 statusfetchStatus에 대해 알 필요가 있다.

  • status : data(쿼리 결과값) 에 대한 상태. pending, error, success로 분류된다.
  • fetchStatus : queryFn에 대한 정보를 나타냄. fetching, paused, idle세가지 상태로 구분된다.

왜 둘을 나눠서 다루는걸까?
=> fetchStatus는 네트워크 연결 상태와 관련된 데이터다. 즉, queryFn요청이 진행중인지 아닌지에 대한 상태다.
=> status쿼리 결과값(data)에 대한 상태다.

아하! 그러니까, 함수의 요청 상태와 결과에 대한 상태구나.
그러면 isLoaidngisPending은 무슨 차이일까?

  • isPending : status에서 파생된 상태. (쿼리 결과값 상태에서 파생됐다.)
  • isLoading : statusfetchStatus가 결합된 상태. 특히 이전버전의 isInitialLoading의 기능을 계승했다. (쿼리 결과값 상태 + 함수의 상태)

아하! 내가 원하는 건 결국 쿼리를 호출했는데, 결과값이 아직 없는 상태(promise의 pending 상태) 였다.
그건 v5에서 isPending이었다.

해결!


Type narrowing in mapping

게임 모드를 나타내는 상태가 있다. 상태에 기반하여 함수를 실행하고싶다.

const [gameMode, setGameMode] = useState<'Start' | 'Finish'>('Start');

if(gameMode === 'Start'){
	startgame()
} else {
	finishgame()
}

이렇게 상태가 두가지라면 if-else를 사용해도 가독성을 해치진 않는다. 하지만 상태가 늘어날수록 if, switch문으로 도배가 될 것이다.
이를 해결하기위해서 매핑을 하면 좋아보인다.

const [gameMode, setGameMode] = useState<'Start' | 'Finish'>('Start');

const mappedGameFn = {
	Start: () => {...},
    Finish: () => {...},
};
    
mappedGameFn[gameMode]();    

다만...TS컴파일러는 이 방법을 모른다. 현재 상태가 Start인지 Finish인지 모르고 유니온타입이기에 StartFn, FinishFn의 형식이 완전히 같아야한다. 이는 Ts컴파일러의 문제점이라고 볼 수 도있다.

https://github.com/microsoft/TypeScript/pull/47109
https://stackoverflow.com/questions/75723250/type-narrowing-of-a-discriminated-union-via-mapping-instead-of-switch

해결법의 핵심은 유니온타입을 제네릭타입으로 바꾸는 것이다. 즉, 함수와 인수가 호환 가능하다는 걸 TS 컴파일러에게 알리는 것이다.

=> 해결하기 위한 타입 작성이 생각보다 엄청 길어진다...
이럴거면 상태가 몇 개 안될땐 그냥 if-else나 switch쓰는게 나을 수도 있을듯?

일단 보류...!!!

profile
모르는 것을 모른다고 하기

0개의 댓글