🦯 너무 많이 바뀐거 아냐..?
좀.. 많이 바뀌었더라구요
버전 올리기 전에 바뀐점들 간단하게 문서읽으면서 정리해봤습니다.
제 기준에서 임팩트 있는 변화들만 적은거지 실제로는 더 많이 바뀌었습니다.
관심이 있으신 분은 해당 문서를 참고해주세요
https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5
더이상 queryClient에서 suspense 모드를 설정해주지 않는다.
서스펜스의 사용을 적절히 추론하지 못하는 것은
리액트쿼리와 타입스크립트를 함께 이용하는 개발자들에게는 매우 불편하게 느껴지는 사항 중 하나였습니다.
그래서 직접 Suspense를 사용하고있는 경우에 대한 커스텀 타입을 제작해서 사용하기도하고
suspensive 라는 라이브러리를 통해 이 문제를 해결하기도 했습니다.
저도 리액트쿼리로 인해 알게된 라이브러리인데
이것저것 편의기능들을 많이 제공해줘서 애용하고있습니다.
reactquery 버전 5부터는 suspensive 라이브러리에서 제공하고있던
useSuspenseQuery, useSupenseQueries , useInfiniteSuspenseQuery를
suspensive라이브러리 없이도 사용할 수 있도록 통합됩니다.
즉 이제는 서스펜스쿼리를 사용하고있다는것만으로도 서스펜스를 사용한다는것을 추론할 수 있으니
queryClient를 생성할때의 옵션에서도 굳이 서스펜스에 대한 정보를 받지 않는 것으로 보입니다.
const SuspenseComponent = ({}: SuspenseComponentProps) => {
const sus = useSuspenseQuery({
queryKey: ['suspense'],
queryFn: async () => {
await new Promise((resolve) => setTimeout(resolve, 5000));
return 'hi suspense';
},
});
return <div>{sus.data}</div>; << 타입스크립트 에러가 나지 않음
};
suspensive 라이브러리에서 지원하고있던 함수들과 동일한 사용법으로 사용해줄 수 있네요
마이그레이션이 어렵지 않을 듯 합니다.
on~ callback 시리즈 쓰지마세요
메인테이너의 블로그에서 쿼리에 대한 on콜백들을 제거하겠다는 열망을 엿볼수 있었는데
v4에서는 디프리케이트였지만 v5에서는 아예 제거를 해버린 모습입니다.
이 변경은 뮤테이션에는 포함되지 않아요
cacheTime은 gcTime이 되었습니다.
캐시라는 워드가 주는 느낌과 실제 동작이 다르다보니
실제 동작을 더 잘표현한다고 생각하는 이름으로 바꾼 모양입니다.
gc는 가비지콜렉팅의 줄임말로 꽤 유명한 단어기도해서 바꾼 모양이네요
useErrorBoundary는 throwOnError로 바뀝니다.
사실 리액트쿼리에서 표현하는 에러바운더리는
리액트 생태계의 클래스형 컴포넌트 Error Boundary를 지칭하는 식으로 사용되어왔습니다.
이걸 throwOnError로 바꾸는 것은 옵션을 특정 라이브러리, 프레임워크에서 독립적으로 만들기 위해서라네요
하이드레이션 api 변경
- import { Hydrate } from '@tanstack/react-query'
+ import { HydrationBoundary } from '@tanstack/react-query'
- <Hydrate state={dehydratedState}>
+ <HydrationBoundary state={dehydratedState}>
<App />
- </Hydrate>
+ </HydrationBoundary>
저 Hydrate라는 이름이 좀 마음에 안들었었는데
사람 생각이 다들 비슷한가봅니다. 더 명확한 이름으로 바뀌네요
약간의 동작도 변경이 되었다고하니 관심있으신분들은 참고하시기발바니다.
아주 많이 쉬워진 낙관적 업데이트
기존에는 낙관적업데이트를 하기 위해서 정말 많은 노력이 필요했습니다..
정말...정말... 눈물이 흐르는데요
const queryClient = useQueryClient()
useMutation({
mutationFn: updateTodo,
// When mutate is called:
onMutate: async (newTodo) => {
// Cancel any outgoing refetches
// (so they don't overwrite our optimistic update)
await queryClient.cancelQueries({ queryKey: ['todos'] })
// Snapshot the previous value
const previousTodos = queryClient.getQueryData(['todos'])
// Optimistically update to the new value
queryClient.setQueryData(['todos'], (old) => [...old, newTodo])
// Return a context object with the snapshotted value
return { previousTodos }
},
// If the mutation fails,
// use the context returned from onMutate to roll back
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previousTodos)
},
// Always refetch after error or success:
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
대충 이런식으로 진행했습니다.
onMutate 콜백을 통해 해당 뮤테이션으로 인해 업데이트 되어야하는 쿼리키를 무효화하고
그 쿼리키에 우리가 업데이트하고자 하는 값을 넣어서 그 쿼리가 갖고있는 상태 자체를 변경시켰습니다.
그런다음에 뮤테이션이 완료되면 쿼리키 무효화를 통해 서버로부터 진짜 업데이트된 데이터를 가져오는 식이었어요
이제는 뮤테이션에서 변경하고자하는 값을 표현할 수 있게됩니다.
예제를 보면서 이해해봅시다.
간단하게 이번 변경을 보여주는 코드를 만들어봤습니다.
const MutationComponent = ({}: MutationComponentProps) => {
const addTextMutation = useMutation({
mutationFn: async (text: string) => {
await new Promise((resolve) => {
setTimeout(resolve, 5000);
});
return text;
},
onSettled: () =>
console.log('여기서 invalidate를 해서 실제로 데이터를 업데이트해요'),
});
return (
<div>
<button onClick={() => addTextMutation.mutate('안녕하세요')}>
좀 더 쉬워진 낙관적 업데이트 버튼
</button>
{addTextMutation.isPending ? (
<div className="">{addTextMutation.variables}</div>
) : null}
</div>
);
};
간단한 뮤테이션을 만들었습니다.
실제로 데이터를 변경요청하는 코드 대신 setTimeout으로 딜레이만 주는 형태인데요
그냥 뮤테이션 함수에 들어온 변수값을 리턴하는 함수입니다.
v5부터는 mutation함수의 매개변수로 들어온 값에
mutation.variables로 접근할 수 있습니다.
보통 매개변수값에 들어간게 그대로 업데이트에 반영되니
대부분의 유스케이스에서 유용하게 사용할 수 있는 기능입니다.
뮤테이션이 pending상태인 경우에만 안녕하세요가 화면에 나오게됩니다.
마치며
리액트쿼리는 메인테이너의 블로그가 너무 유명하다보니
변경점들을 읽으면서 사용자의 입장도 입장이지만 만드는 사람의 입장에서도 생각해보게 되는 것 같습니다.
인상깊게 읽었던 글 중 하나가 라이브러리의 메이저버전이 올라간다는 것은
이전 버전에서 잘못만든게 있다는 것이다. 라는 뉘앙스의 글이었는데
사용자의 변경점도 많았지만 내부의 기술적인 변경과
더 좋은 의미를 위한 프로퍼티명 변경과 같은 변화들도 많았다는 점이 인상깊더라구요
버전을 올리는 건.. 조금 미루고싶지만..
빨리 버전을 올려보고 싶다는 욕심이 생기는 변경점들이었던 것 같습니다.
'react' 카테고리의 다른 글
리액트 라이브러리 없이 캘린더, 달력 구현하기 (4) | 2023.10.31 |
---|---|
실습과 함께 배우는 리액트 쿼리로 낙관적 업데이트 하는 법 (1) | 2023.10.15 |
리액트 타이핑효과 커스텀 훅 만들기 (0) | 2023.08.15 |
what is react server components 이..이거 뭐냐? (2) | 2023.08.07 |
리액트를 사용하는 이유는 무엇일까? (2) | 2023.08.04 |