8.2 KiB
title, source_type, url, archive_url, related_branches, related_projects, tags, created
| title | source_type | url | archive_url | related_branches | related_projects | tags | created | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| TanStack Query — persistQueryClient / dehydrate·hydrate | official-doc | https://tanstack.com/query/latest/docs/framework/react/plugins/persistQueryClient |
|
|
|
2026-07-28 |
TanStack Query — persistQueryClient / dehydrate·hydrate
Layer:
raw/— 외부 자료의 원문 발췌·출처 기록.
활용 branch (필수, 최소 1개+)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
[[raw/branch-notes/feature-frontend-cache-tier-cross-tab-invalidation-contract]] |
version 불일치 시 부분 복원 없이 전량 폐기(D1), 복원과 렌더의 순서(D6), 영속 대상 선별과 직렬화 책임(D7) |
출처
- 원본 URL: https://tanstack.com/query/latest/docs/framework/react/plugins/persistQueryClient
- 보조 URL: https://tanstack.com/query/latest/docs/framework/react/reference/hydration
- 아카이브 URL:
- 저자 / 조직: TanStack (TanStack Query 공식 문서)
- 발행일: (문서 지속 갱신, v5 기준)
- 마지막 확인일: 2026-07-28
왜 저장했는지
이 repo 의 기존 TanStack 발췌(raw/official-docs/tanstack-query-server-state-official)는 server state 원칙만 담고 있어 캐시 영속을 다루지 않는다. CachePersistencePort 를 설계하면서 세 가지를 확인해야 했다. (a) 라이브러리가 버전 불일치 캐시를 부분 복원하는지 폐기하는지, (b) 복원이 렌더와 경합하는지, (c) 어떤 query 가 기본적으로 영속 대상인지. 세 가지 모두 공식 문서가 직접 답한다.
핵심 인용
[§persistQueryClient — buster] "If the cache that is found does not also have that buster string, it will be discarded."
[§persistQueryClient — maxAge] "The max-allowed age of the cache in milliseconds. If a persisted cache is found that is older than this time, it will be silently discarded (defaults to 24 hours)"
[§persistQueryClient — How it works] "If data is found to be any of the following: 1. expired (see
maxAge) 2. busted (seebuster)... the persisterremoveClient()is called and the cache is immediately discarded."
[§persistQueryClient] "
createSyncStoragePersisterandcreateAsyncStoragePersisterthrottle this action to happen at most every 1 second to save on potentially expensive writes."
[§persistQueryClient — PersistQueryClientProvider] "However, restoring is asynchronous, because all persisters are async by nature, which means that if you render your App while you are restoring, you might get into race conditions if a query mounts and fetches at the same time."
[§hydration — dehydrate] "It only includes currently successful queries by default."
[§hydration — dehydrate Options] "
shouldDehydrateQuery— Whether to dehydrate queries." / "Defaults to only including successful queries"
[§hydration — dehydrate Returns] "This result is not in serialized form, you need to do that yourself if desired"
[§hydration — hydrate Limitations] "If the queries you're trying to hydrate already exist in the queryCache,
hydratewill only overwrite them if the data is newer than the data present in the cache."
추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| C1 | 저장된 캐시의 buster 문자열이 일치하지 않으면 그 캐시는 폐기된다 | [§buster] "If the cache that is found does not also have that buster string, it will be discarded." | official-reference |
persistQueryClient 복원 경로 |
buster 를 무엇으로 구성해야 하는지 — 문자열 내용은 소비자가 정한다 |
| C2 | buster 불일치·만료 시 removeClient() 가 호출되고 캐시는 즉시 폐기된다 — 부분 복원 경로가 없다 |
[§How it works] "the persister removeClient() is called and the cache is immediately discarded" |
official-reference |
복원 실패 처리 | 폐기가 사용자에게 고지되어야 한다는 뜻은 아님 |
| C3 | maxAge 기본값은 24시간이며 초과분은 조용히 폐기된다 |
[§maxAge] "it will be silently discarded (defaults to 24 hours)" | official-reference |
라이브러리 기본값 | 24시간이 우리 계약의 TTL 이라는 뜻은 아님 — 우리 값은 FE-REG-STORAGE 가 정한다 |
| C4 | 번들 제공 persister 는 write 를 최대 1초에 1회로 throttle 한다 | [§persistQueryClient] "throttle this action to happen at most every 1 second to save on potentially expensive writes" | official-reference |
createSyncStoragePersister·createAsyncStoragePersister |
우리 custom adapter 의 적정 간격이 1초라는 뜻은 아님 — 번들 구현의 선택값이다 |
| C5 | 복원은 비동기이며, 복원 중 렌더하면 query mount·fetch 와 경합이 발생할 수 있다 | [§PersistQueryClientProvider] "if you render your App while you are restoring, you might get into race conditions if a query mounts and fetches at the same time" | official-reference |
모든 async persister | 경합이 항상 눈에 보이는 오류로 나타난다는 뜻은 아님 |
| C6 | dehydrate 는 기본적으로 성공한 query 만 포함한다 |
[§dehydrate] "It only includes currently successful queries by default." | official-reference |
영속 대상 선별 | error/pending query 를 영속하면 안 된다는 금지 규칙까지는 아님 — 기본값일 뿐 |
| C7 | dehydrate 결과는 직렬화된 형태가 아니며 직렬화는 소비자 책임이다 |
[§dehydrate Returns] "This result is not in serialized form, you need to do that yourself if desired" | official-reference |
영속 adapter | 어떤 직렬화 형식을 써야 하는지 |
| C8 | hydrate 는 이미 캐시에 있는 query 를 더 새로운 데이터일 때만 덮어쓴다 |
[§hydrate Limitations] "hydrate will only overwrite them if the data is newer than the data present in the cache" |
official-reference |
복원 시 병합 | "더 새롭다"의 판정 기준이 무엇인지 |
적용 경계
- 이 자료가 직접 증명하는 것:
C1·C2: 버전 불일치 캐시의 처리는 부분 복원이 아니라 전량 폐기가 라이브러리의 기존 동작이다C5: 복원과 렌더를 겹치면 경합이 생기므로 gating 이 필요하다C6~C8: 영속 대상 기본 선별, 직렬화 책임 위치, 복원 시 병합 규칙
- 이 자료가 증명하지 않는 것:
- 파티션 키를
releaseId·configSchemaVersion·apiContractVersion세 값으로 구성해야 한다는 것 —C1은 buster 가 문자열이라는 것만 말한다. 구성은 project decision 이다 CachePersistencePort를QueryCachePort와 분리해야 한다는 것 — 문서는 단일queryClient를 전제한다- 우리 adapter 의 throttle 값 (
C4는 번들 persister 의 선택값)
- 파티션 키를
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
C3의 24시간 기본값과FE-REG-STORAGE의QUERY_CACHE_SNAPSHOTTTL 이 충돌하지 않는지C8의 "newer" 판정이 우리 파티션 폐기 규칙보다 먼저 적용되는지 (폐기가 우선이면 무관)
메모
- 인용 1 해석 후보 (미검증):
C1+C2는 branch 의D1("불일치 시 복원하지 않고 폐기, 부분 복원 금지")이 자체 발명이 아니라 채택한 라이브러리의 기존 동작과 같은 방향임을 보여준다. 다만 세 값 tuple 구성은 여전히 project-local 이다. - 인용 2 해석 후보 (미검증):
C5때문에CachePersistencePort.restore()는 bootstrap 단계에서 await 되어야 하고, 복원 실패는 부팅을 막지 않고 메모리 캐시로 진행해야 한다(§8.2CACHE_PERSISTENCE_FAILURE와 정합). - 추가로 봐야 할 동일 출처 페이지:
createAsyncStoragePersister,broadcastQueryClientexperimental plugin
관련
- 같은 주제 다른 official-doc:
[[raw/official-docs/tanstack-query-server-state-official]],[[raw/official-docs/mdn-broadcastchannel-storage-event]] - 이 자료를 인용한 wiki 요약: 생성 전