내가 열심히 노는동안 언제나오나 싶었던 v5가 나왔다!
그것도 많은 변화를 가지고!! (문서 링크)
언제 다 마이그레이션 하나 싶지만 아무튼 알아보자.. ㅎ
모든 변경점을 적진 않았습니다.. ㅎ
1. Supports a single signature, one object
- useQuery 및 기타 등등 훅들은 아래와 같이 여러 형태로 사용되었는데 유지보수 및 타입스크립트 측면 등의 이유로 이제는 한가지 형태로 통일되었다.
> 사용하는 입장에서도 하나로 통일되는게 컨벤션 안 맞춰도 되고 좋은 것 같다.
// ASIS: 여러 방법으로 사용 가능
useQuery(queryKey, queryFn, options);
useQuery(queryKey, options);
useQuery(options);
// TOBE: 한가지 방법으로만 사용 가능
useQuery(options);
이런 것들도 바꼈다. 참고하시길..!
변경할 생각에 눈 앞이 아득해진다면? Codemod
- 고통받을 개발자들을 생각했는지 마이그레이션 편하게? 하는 방법을 추가해놓았다. 약간 감동이다. 몰랐는데 앞으로도 애용해야겠다.
npx jscodeshift@latest ./src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/build/codemods/src/v5/remove-overloads/remove-overloads.js
ASIS
TOBE
잘 변경되는데 prettier, eslint autofix 를 해주진 않아서 스크립트 실행 후 Formatting 작업을 다시 해주긴 해야한다.
2. Callbacks on useQuery (and QueryObserver) have been removed (link)
- useQuery 의 onSuccess, onError, onSetteled 같은 콜백 옵션이 사라졌다.
- 나또한 이런 생각으로 callback 사용하는걸 좋아했다. 물론 useQuery 에는 Suspense 도입 이후 잘 안 썼지만 ㅎ
onError
global-cache level 에서 콜백을 세팅하기
- 쿼리당 한 번만 호출됨
// 서버의 에러메세지를 그대로 사용하는 경우
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error) =>
toast.error(`Something went wrong: ${error.message}`),
}),
})
// custom error message 를 사용하고 싶은 경우
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
if (query.meta.errorMessage) {
toast.error(query.meta.errorMessage)
}
},
}),
})
export function useTodos() {
return useQuery({
queryKey: ['todos', 'list'],
queryFn: fetchTodos,
meta: {
errorMessage: 'Failed to fetch todos',
},
})
}
기존에는 아래와 같이 사용했었다.
원래는 axios 의 interceptor 레벨에서 에러 토스트를 띄어주었으나, 에러 토스트를 커스텀하게 하고 싶을 때 할 수가 없어서
useQuery 의 글로벌 콜백 onError 에 넣어줬었고
공용 에러 토스트를 사용하고 싶지 않으면 각 쿼리에서 onError 콜백을 통해 overwrite 해버리게끔 처리했다.
const globalQueryClientConfig: QueryClientConfig = {
defaultOptions: {
queries: {
...생략
onError: onGlobalQueryError,
},
mutations: {
...생략
onError: onGlobalQueryError,
},
},
};
const onGlobalQueryError = (e) => {
if (!e?.code) {
return;
}
if (e.code < 0) {
/** toast 겹치는 이슈로 각 api 에서 따로 에러 액션을 정의해서 사용 */
toast.error(e.message);
}
};
> 이 정도는 onGlobalQuery Error 위치만 변경해주면 돼서 쉽게 변경 가능할 것 같다.
isError flag 사용해서 처리하기
- 여기서부터는 이 url 을 참고했다
- 이렇게 사용할 때는 if문을 data 존재 여부 > error 존재 여부 > else 로더 순으로 해야 백그라운드 에러 관련 이슈를 해결할 수 있다. 하지만 항상 프로젝트 바이 프로젝트 이기 때문에 상황 봐서 알맞은 순서로 사용하면 된다.
function TodoList() {
const todos = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos
})
if (todos.isPending) {
return 'Loading...'
}
// ✅ standard error handling
// could also check for: todos.status === 'error'
if (todos.isError) {
return 'An error occurred'
}
return (
<div>
{todos.data.map((todo) => (
<Todo key={todo.id} {...todo} />
))}
</div>
)
}
ErrorBoundaries 사용
- throwOnError option 을 켜고 ErrorBoundary 로 덮어주면 끝
onSuccess
- 아래와 같이 onSuccess 에서 setState 를 하지 말라고 되어 있다. 왤까?
> 불필요한 렌더 사이클이 추가될 수도 있다.
> 렌더 사이클 중 잘못된 값으로 렌더링 될 수 있다.
> staleTime 사용시 onSuccess 가 항상 호출되지만은 않는다
export function useTodos() {
const [todoCount, setTodoCount] = React.useState(0)
const { data: todos } = useQuery({
queryKey: ['todos', 'list'],
queryFn: fetchTodos,
//😭 please don't
onSuccess: (data) => {
setTodoCount(data.length)
},
})
return { todos, todoCount }
}
3. useQuery 의 Return 값중 remove 제거
- query.remove 대신 queryClient.removeQueries({queryKey}) 사용
4. 최소 요구 버전 변경
- typescript 4.7
- react 18
4. 이름 변경
- cacheTime > gcTime
- useErrorBoundary > throwOnError
- status : loading > pending
- isLoading > isPending
- isInitialLoading > isLoading
- hasQueryKey > hasKey
5. Error 의 타입 변경 (unknown > Error)
- 에러 타이핑 하기 (링크)
6. retry 기본값 변경 3 > 0
7. 새로운 hook 추가
- useSuspenseQuery
- useSuspenseInfiniteQuery
- useSuspenseQueries
- 기존에 suspense 와 함께 사용할 때 data의 타입이 undefined 와 함께 추론되던 문제점을 해결했다.
그리고 이 hook 이 추가되면서 내가 useQuery 사용하던 패턴을 변경해야겠다는 생각이 들었다.
ASIS
useGetSomethingQuery 라고 useQuery함수를 option을 변경하끔 만들어놓고 사용
특수한 상황 제외하고 useGetSomethingQuery, queryKey 정도만 export 하여 사용
TOBE
QueryKey, QueryFn 을 export 하고 useQuery 구문은 그때그때 사용
만약 QueryKey와 QueryFn 을 함께 쓰고 싶다면 queryOptions 사용 (링크)
'내가 경험한 것 > 1.5' 카테고리의 다른 글
eslint config npm에 올리기 (0) | 2024.02.03 |
---|---|
prettier config npm 에 올리기 (0) | 2024.02.02 |
FE 과제 회고1 (4) | 2024.01.06 |
나를 괴롭히던 타입스크립트 - lodash 편 (2) | 2023.12.25 |
나를 괴롭히던 타입스크립트 - axios interceptor 편 (2) | 2023.12.23 |