feat: 공식 문서 근거자료, 브랜치 기능 문서 작성
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
---
|
||||
title: TanStack Query — persistQueryClient / dehydrate·hydrate
|
||||
source_type: official-doc
|
||||
url: https://tanstack.com/query/latest/docs/framework/react/plugins/persistQueryClient
|
||||
archive_url:
|
||||
related_branches: [feature-frontend-cache-tier-cross-tab-invalidation-contract]
|
||||
related_projects: [ca-skeleton-frontend]
|
||||
tags: [frontend, server-state, cache, persistence, tanstack-query]
|
||||
created: 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 (see `buster`)... the persister `removeClient()` is called and the cache is immediately discarded."
|
||||
|
||||
> [§persistQueryClient] "`createSyncStoragePersister` and `createAsyncStoragePersister` throttle 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, `hydrate` will 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_SNAPSHOT` TTL 이 충돌하지 않는지
|
||||
- `C8` 의 "newer" 판정이 우리 파티션 폐기 규칙보다 먼저 적용되는지 (폐기가 우선이면 무관)
|
||||
|
||||
## 메모
|
||||
|
||||
- 인용 1 해석 후보 (미검증): `C1`+`C2` 는 branch 의 `D1`("불일치 시 복원하지 않고 폐기, 부분 복원 금지")이 **자체 발명이 아니라 채택한 라이브러리의 기존 동작과 같은 방향**임을 보여준다. 다만 세 값 tuple 구성은 여전히 project-local 이다.
|
||||
- 인용 2 해석 후보 (미검증): `C5` 때문에 `CachePersistencePort.restore()` 는 bootstrap 단계에서 await 되어야 하고, 복원 실패는 부팅을 막지 않고 메모리 캐시로 진행해야 한다(§8.2 `CACHE_PERSISTENCE_FAILURE` 와 정합).
|
||||
- 추가로 봐야 할 동일 출처 페이지: `createAsyncStoragePersister`, `broadcastQueryClient` experimental plugin
|
||||
|
||||
## 관련
|
||||
|
||||
- 같은 주제 다른 official-doc: `[[raw/official-docs/tanstack-query-server-state-official]]`, `[[raw/official-docs/mdn-broadcastchannel-storage-event]]`
|
||||
- 이 자료를 인용한 wiki 요약: 생성 전
|
||||
Reference in New Issue
Block a user