데이터 가져오기 라이브러리(react-query, swr, rtk-query 등)에 대한 자동 정규화 및 데이터 업데이트
소개
동기 부여
설치
필수 조건
배열의 정규화
디버깅
성능
통합
예
normy
는 애플리케이션 데이터를 자동으로 정규화할 수 있는 라이브러리입니다. 그런 다음 데이터가 정규화되면 대부분의 경우 데이터가 자동으로 업데이트될 수 있습니다.
normy
의 핵심, 즉 애플리케이션에서 직접 사용되지 않는 @normy/core
라이브러리에는 즐겨 사용하는 데이터 가져오기 라이브러리와 쉽게 통합할 수 있는 논리가 내부에 있습니다. 이미 react-query
, swr
및 RTK Query
와의 공식 통합이 있습니다. 다른 페칭 라이브러리를 사용하는 경우 Github 문제가 발생할 수 있으므로 추가될 수도 있습니다.
normy
실제로 무엇을 하는지 이해하려면 예제를 보는 것이 가장 좋습니다. react-query
사용한다고 가정해 보겠습니다. 그런 다음 다음과 같은 방법으로 코드를 리팩터링할 수 있습니다.
'반응'에서 반응을 가져옵니다; 수입 { 쿼리클라이언트 제공자, 쿼리클라이언트, 사용쿼리클라이언트, } from '@tanstack/react-query';+ import { QueryNormalizerProvider } from '@normy/react-query'; const queryClient = 새로운 QueryClient(); const 책 = () => { const queryClient = useQueryClient(); const { 데이터: booksData = [] } = useQuery(['books'], () => 약속.해결([ { id: '1', 이름: '이름 1', 작성자: { id: '1001', 이름: 'User1' } }, { id: '2', 이름: '이름 2', 작성자: { id: '1002', 이름: 'User2' } }, ]), ); const { 데이터: bookData } = useQuery(['book'], () => 약속.해결({ 아이디: '1', 이름: '이름 1', 작성자: { ID: '1001', 이름: 'User1' }, }), ); const updateBookNameMutation = useMutation({ mutationFn: () => ({ 아이디: '1', name: '이름 1 업데이트됨', }),- onSuccess: mutationData => {- queryClient.setQueryData(['books'], data =>- data.map(book =>- book.id === mutationData.id ? { ...book, . ..mutationData } : book,- ),- );- queryClient.setQueryData(['book'], data =>- data.id === mutationData.id ? { ...data, ...mutationData } : 데이터,- );- },}); const updateBookAuthorMutation = useMutation({ mutationFn: () => ({ 아이디: '1', 작성자: { ID: '1004', 이름: 'User4' }, }),- onSuccess: mutationData => {- queryClient.setQueryData(['books'], data =>- data.map(book =>- book.id === mutationData.id ? { ...book, . ..mutationData } : book,- ),- );- queryClient.setQueryData(['book'], data =>- data.id === mutationData.id ? { ...data, ...mutationData } : 데이터,- );- },}); const addBookMutation = useMutation({ mutationFn: () => ({ 아이디: '3', 이름: '이름 3', 작성자: { ID: '1003', 이름: 'User3' }, }), // 최상위 배열이 포함된 데이터의 경우 여전히 수동으로 데이터를 업데이트해야 합니다. onSuccess: mutationData => { queryClient.setQueryData(['books'], data => data.concat(mutationData)); }, }); // 일부 JSX를 반환합니다. }; const 앱 = () => (+ <QueryNormalizerProvider queryClient={queryClient}> <QueryClientProvider 클라이언트={queryClient}> <책 /> </QueryClientProvider>+ </QueryNormalizerProvider> );
따라서 보시다시피 최상위 어레이를 제외하고 더 이상 수동 데이터 업데이트가 필요하지 않습니다. 이는 특정 돌연변이가 여러 쿼리에 대한 데이터를 업데이트해야 하는 경우 특히 유용합니다. 업데이트를 수동으로 수행하는 것은 장황할 뿐만 아니라 업데이트할 쿼리를 정확히 알아야 합니다. 쿼리가 많을수록 normy
으로 얻을 수 있는 이점은 더 커집니다.
어떻게 작동하나요? 기본적으로 id
키가 있는 모든 객체는 해당 ID로 구성됩니다. 이제 키 id
있는 모든 객체가 정규화됩니다. 이는 단순히 ID로 저장된다는 의미입니다. 동일한 ID를 가진 일치하는 개체가 이미 있는 경우 새 개체가 이미 상태에 있는 개체와 깊이 병합됩니다. 따라서 변형의 서버 응답 데이터가 { id: '1', title: 'new title' }
인 경우 이 라이브러리는 모든 종속 쿼리에 대해 id: '1'
인 개체의 title
업데이트하도록 자동으로 파악합니다.
또한 깊이에 관계없이 ID가 있는 중첩 개체에서도 작동합니다. ID가 있는 객체에 ID가 있는 다른 객체가 있는 경우 해당 객체는 별도로 정규화되고 상위 객체는 해당 중첩 객체에 대한 참조만 갖게 됩니다.
패키지를 설치하려면 다음을 실행하세요.
$ npm install @normy/react-query
아니면 그냥 CDN( https://unpkg.com/@normy/react-query
)을 사용해도 됩니다.
패키지를 설치하려면 다음을 실행하세요.
$ npm install @normy/swr
아니면 그냥 CDN( https://unpkg.com/@normy/swr
)을 사용해도 됩니다.
패키지를 설치하려면 다음을 실행하세요.
$ npm install @normy/rtk-query
또는 그냥 CDN( https://unpkg.com/@normy/rtk-query
을 사용할 수도 있습니다.
react-query
, swr
또는 rtk-query
아닌 다른 라이브러리에 플러그인을 작성하려면 다음을 수행하세요.
$ npm install @normy/core
아니면 그냥 CDN( https://unpkg.com/@normy/core
을 사용해도 됩니다.
플러그인 작성 방법을 보려면 지금은 @normy/react-query
소스 코드를 확인하세요. 매우 쉽습니다. 나중에 가이드가 작성될 예정입니다.
자동 정규화가 작동하려면 다음 조건이 충족되어야 합니다.
객체를 식별하는 표준화된 방법이 있어야 합니다. 일반적으로 이는 키 id
로 수행됩니다.
ID는 객체 유형뿐만 아니라 전체 앱에서 고유해야 합니다. 그렇지 않은 경우 ID에 무언가를 추가해야 합니다. GraphQL 세계에서도 동일한 작업을 수행해야 하며 일반적으로 _typename
추가합니다.
동일한 ID를 가진 개체는 일관된 구조를 가져야 하며, 한 쿼리에서 책과 같은 개체에 title
키가 있는 경우 갑자기 name
아닌 다른 쿼리에서도 title
이어야 합니다.
이러한 요구 사항을 충족하기 위해 createQueryNormalizer
에 전달할 수 있는 함수, 즉 getNormalizationObjectKey
가 있습니다.
getNormalizationObjectKey
첫 번째 지점에서 도움이 될 수 있습니다. 예를 들어 _id
키와 같이 객체를 다르게 식별하는 경우 getNormalizationObjectKey: obj => obj._id
전달할 수 있습니다.
getNormalizationObjectKey
하면 두 번째 요구 사항도 통과할 수 있습니다. 예를 들어, ID가 고유하지만 전체 앱에서는 아니지만 객체 유형 내에서는 getNormalizationObjectKey: obj => obj.id && obj.type ? obj.id + obj.type : undefined
또는 이와 유사한 것. 이것이 가능하지 않다면 접미사를 직접 계산할 수 있습니다. 예를 들면 다음과 같습니다.
const getType = obj => { if (obj.bookTitle) {return '책'; } if (obj.surname) {return '사용자'; } 정의되지 않은 반환;};createQueryNormalizer(queryClient, { getNormalizationObjectKey: obj =>obj.id && getType(obj) && obj.id + getType(obj),});
3번 항목은 항상 충족되어야 합니다. 그렇지 않은 경우에는 백엔드 개발자에게 표준화되고 일관성을 유지하도록 요청해야 합니다. 최후의 수단으로 귀하가 직접 응답을 수정할 수 있습니다.
불행하게도 더 이상 데이터를 수동으로 업데이트할 필요가 없다는 의미는 아닙니다. 일부 업데이트는 여전히 평소처럼 수동으로 수행해야 합니다. 즉, 배열에서 항목을 추가하고 제거해야 합니다. 왜? REMOVE_BOOK
돌연변이를 상상해 보세요. 이 책은 많은 검색어에 나타날 수 있지만, 도서관에서는 어떤 검색어에서 해당 책을 제거할지 알 수 없습니다. ADD_BOOK
에도 동일하게 적용됩니다. 도서관은 책을 어떤 쿼리에 추가해야 하는지, 심지어 어떤 배열 인덱스를 추가해야 하는지 알 수 없습니다. SORT_BOOKS
와 같은 작업도 마찬가지입니다. 이 문제는 최상위 배열에만 영향을 미칩니다. 예를 들어, likedByUsers
와 같은 일부 ID와 다른 키가 있는 책이 있는 경우 likedByUsers
에 업데이트된 목록이 포함된 새 책을 반환하면 자동으로 다시 작동합니다.
하지만 라이브러리의 향후 버전에서는 몇 가지 추가 포인터를 사용하여 위의 업데이트도 수행할 수 있습니다!
normy
어떤 데이터 조작이 실제로 수행되는지 관심이 있다면 devLogging
옵션을 사용할 수 있습니다.
<QueryNormalizerProvider 쿼리클라이언트={쿼리클라이언트} NormalizerConfig={{ devLogging: true }}> {어린이}</QueryNormalizerProvider>
기본적으로 false
이며, true
로 설정하면 쿼리가 설정되거나 제거될 때 콘솔 정보를 볼 수 있습니다.
이는 개발에서만 작동합니다. true
전달하더라도 프로덕션에서는 로깅이 수행되지 않습니다(정확히 process.env.NODE_ENV === 'production'
인 경우). NODE_ENV
는 일반적으로 webpack
과 같은 모듈 번들러에 의해 설정되므로 NODE_ENV
직접 설정하는 것에 대해 걱정할 필요가 없습니다.
언제나 그렇듯이 모든 자동화에는 비용이 따릅니다. 나중에 일부 벤치마크가 추가될 수 있지만 현재 수동 테스트에서는 데이터에 수만 개의 정규화된 개체가 없으면 오버헤드가 눈에 띄지 않는 것으로 나타났습니다. 그러나 성능을 향상시킬 수 있는 몇 가지 유연한 방법이 있습니다.
데이터 업데이트가 있는 쿼리와 데이터를 업데이트해야 하는 변형만 정규화할 수 있습니다. 즉, 데이터의 일부만 정규화할 수 있습니다. 이를 수행하는 방법은 통합 문서를 확인하세요.
1.
과 비슷하지만 매우 큰 데이터가 포함된 쿼리 및 변형의 경우입니다.
돌연변이 반응의 데이터가 정규화된 저장소의 데이터와 실제로 다른지 확인하는 최적화 기능이 내장되어 있습니다. 동일한 경우 종속 쿼리는 업데이트되지 않습니다. 따라서 돌연변이 데이터에는 실제로 다를 수 있는 것만 포함하는 것이 좋습니다. 그러면 불필요한 정규화 및 쿼리 업데이트를 방지할 수 있습니다.
이를 지원하는 라이브러리에서 structuralSharing
옵션을 비활성화하지 마십시오. 업데이트 후 쿼리 데이터가 업데이트 전과 참조적으로 동일하면 이 쿼리는 정규화되지 않습니다. 이는 특히 재초점 시 다시 가져온 후에 성능이 크게 최적화되며, 일반적으로 동일한 데이터로 여러 쿼리를 동시에 업데이트할 수 있습니다.
getNormalizationObjectKey
함수를 사용하여 실제로 정규화해야 하는 객체를 전역적으로 설정할 수 있습니다. 예를 들어:
<QueryNormalizerProvider 쿼리클라이언트={쿼리클라이언트} NormalizerConfig={{getNormalizationObjectKey: obj => (obj.normalized ? obj.id : 정의되지 않음), }}> {어린이}</QueryNormalizerProvider>
또한, 향후 몇 가지 성능별 옵션이 추가될 예정입니다.
현재 데이터 가져오기 라이브러리와의 세 가지 공식 통합, 즉 react-query
, swr
및 rtk-query
가 있습니다. 특정 통합에 대한 전용 문서를 참조하세요.
반응 쿼리
SW
rtk 쿼리
이 패키지가 실제 애플리케이션에서 어떻게 사용될 수 있는지 예제를 시도해 볼 것을 적극 권장합니다.
현재 다음과 같은 예가 있습니다.
반응 쿼리
trpc
SW
rtk 쿼리
MIT