-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a more complex example for persistence. This examples demonstra…
…tes how to selectively persist queries to different persisters.
- Loading branch information
1 parent
b858927
commit 325b2a7
Showing
18 changed files
with
629 additions
and
68 deletions.
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
examples/angular/multiple-persisters/.devcontainer/devcontainer.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"name": "Node.js", | ||
"image": "mcr.microsoft.com/devcontainers/javascript-node:22" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// @ts-check | ||
|
||
/** @type {import('eslint').Linter.Config} */ | ||
const config = {} | ||
|
||
module.exports = config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# TanStack Query Angular multiple persisters example | ||
|
||
To run this example: | ||
|
||
- `npm install` or `yarn` or `pnpm i` or `bun i` | ||
- `npm run start` or `yarn start` or `pnpm start` or `bun start` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
{ | ||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", | ||
"version": 1, | ||
"cli": { | ||
"packageManager": "pnpm", | ||
"analytics": false, | ||
"cache": { | ||
"enabled": false | ||
} | ||
}, | ||
"newProjectRoot": "projects", | ||
"projects": { | ||
"multiple-persisters": { | ||
"projectType": "application", | ||
"schematics": { | ||
"@schematics/angular:component": { | ||
"inlineTemplate": true, | ||
"inlineStyle": true, | ||
"skipTests": true | ||
}, | ||
"@schematics/angular:class": { | ||
"skipTests": true | ||
}, | ||
"@schematics/angular:directive": { | ||
"skipTests": true | ||
}, | ||
"@schematics/angular:guard": { | ||
"skipTests": true | ||
}, | ||
"@schematics/angular:interceptor": { | ||
"skipTests": true | ||
}, | ||
"@schematics/angular:pipe": { | ||
"skipTests": true | ||
}, | ||
"@schematics/angular:resolver": { | ||
"skipTests": true | ||
}, | ||
"@schematics/angular:service": { | ||
"skipTests": true | ||
} | ||
}, | ||
"root": "", | ||
"sourceRoot": "src", | ||
"prefix": "app", | ||
"architect": { | ||
"build": { | ||
"builder": "@angular/build:application", | ||
"options": { | ||
"outputPath": "dist/multiple-persisters", | ||
"index": "src/index.html", | ||
"browser": "src/main.ts", | ||
"polyfills": ["zone.js"], | ||
"tsConfig": "tsconfig.app.json", | ||
"assets": ["src/favicon.ico", "src/assets"], | ||
"styles": ["src/styles.css"], | ||
"scripts": [] | ||
}, | ||
"configurations": { | ||
"production": { | ||
"budgets": [ | ||
{ | ||
"type": "initial", | ||
"maximumWarning": "500kb", | ||
"maximumError": "1mb" | ||
}, | ||
{ | ||
"type": "anyComponentStyle", | ||
"maximumWarning": "2kb", | ||
"maximumError": "4kb" | ||
} | ||
], | ||
"outputHashing": "all" | ||
}, | ||
"development": { | ||
"optimization": false, | ||
"extractLicenses": false, | ||
"sourceMap": true | ||
} | ||
}, | ||
"defaultConfiguration": "production" | ||
}, | ||
"serve": { | ||
"builder": "@angular/build:dev-server", | ||
"configurations": { | ||
"production": { | ||
"buildTarget": "multiple-persisters:build:production" | ||
}, | ||
"development": { | ||
"buildTarget": "multiple-persisters:build:development" | ||
} | ||
}, | ||
"defaultConfiguration": "development" | ||
}, | ||
"extract-i18n": { | ||
"builder": "@angular/build:extract-i18n", | ||
"options": { | ||
"buildTarget": "multiple-persisters:build" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
{ | ||
"name": "@tanstack/query-example-angular-multiple-persisters", | ||
"type": "module", | ||
"scripts": { | ||
"ng": "ng", | ||
"start": "ng serve", | ||
"build": "ng build", | ||
"watch": "ng build --watch --configuration development" | ||
}, | ||
"private": true, | ||
"dependencies": { | ||
"@angular/common": "^19.1.0-next.0", | ||
"@angular/compiler": "^19.1.0-next.0", | ||
"@angular/core": "^19.1.0-next.0", | ||
"@angular/platform-browser": "^19.1.0-next.0", | ||
"@angular/platform-browser-dynamic": "^19.1.0-next.0", | ||
"@tanstack/angular-query-experimental": "^5.62.3", | ||
"@tanstack/angular-query-persist-client-experimental": "^5.62.3", | ||
"@tanstack/query-sync-storage-persister": "^5.62.3", | ||
"rxjs": "^7.8.1", | ||
"tslib": "^2.6.3", | ||
"zone.js": "^0.15.0" | ||
}, | ||
"devDependencies": { | ||
"@angular/build": "^19.0.2", | ||
"@angular/cli": "^19.0.2", | ||
"@angular/compiler-cli": "^19.1.0-next.0", | ||
"autoprefixer": "^10.4.20", | ||
"postcss": "^8.4.49", | ||
"tailwindcss": "^3.4.7", | ||
"typescript": "5.7.2" | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
examples/angular/multiple-persisters/src/app/app.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { ChangeDetectionStrategy, Component } from '@angular/core' | ||
import { UserPreferencesComponent } from './components/user-preferences.component' | ||
import { SessionDataComponent } from './components/session-data.component' | ||
|
||
@Component({ | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
selector: 'app-root', | ||
standalone: true, | ||
template: ` | ||
<div class="min-h-screen bg-gray-100 p-8"> | ||
<div class="max-w-4xl mx-auto"> | ||
<h1 class="text-3xl font-bold text-gray-800 mb-8"> | ||
TanStack Query Persistence Demo | ||
</h1> | ||
<p class="text-gray-600 mb-4 leading-relaxed"> | ||
This demo illustrates how to selectively persist queries to different | ||
persisters. By leveraging shouldDehydrateQuery, it is possible to | ||
strategically cache data in multiple persisters based on specific | ||
query requirements. | ||
</p> | ||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8"> | ||
<user-preferences /> | ||
<session-data /> | ||
</div> | ||
</div> | ||
</div> | ||
`, | ||
imports: [UserPreferencesComponent, SessionDataComponent], | ||
}) | ||
export class AppComponent {} |
60 changes: 60 additions & 0 deletions
60
examples/angular/multiple-persisters/src/app/app.config.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { | ||
provideHttpClient, | ||
withFetch, | ||
withInterceptors, | ||
} from '@angular/common/http' | ||
import { | ||
QueryClient, | ||
provideTanStackQuery, | ||
withDevtools, | ||
} from '@tanstack/angular-query-experimental' | ||
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister' | ||
import { withPersistQueryClient } from '@tanstack/angular-query-persist-client-experimental' | ||
import { mockInterceptor } from './interceptor/mock-api.interceptor' | ||
import type { ApplicationConfig } from '@angular/core' | ||
|
||
const localStoragePersister = createSyncStoragePersister({ | ||
storage: window.localStorage, | ||
}) | ||
|
||
const sessionStoragePersister = createSyncStoragePersister({ | ||
storage: window.sessionStorage, | ||
}) | ||
|
||
export const appConfig: ApplicationConfig = { | ||
providers: [ | ||
provideHttpClient(withFetch(), withInterceptors([mockInterceptor])), | ||
provideTanStackQuery( | ||
new QueryClient({ | ||
defaultOptions: { | ||
queries: { | ||
gcTime: 1000 * 60 * 60 * 24, // 24 hours | ||
}, | ||
}, | ||
}), | ||
withDevtools(), | ||
withPersistQueryClient([ | ||
{ | ||
persistOptions: { | ||
persister: localStoragePersister, | ||
dehydrateOptions: { | ||
shouldDehydrateQuery: (query) => | ||
query.state.status === 'success' && | ||
query.queryKey[0] === 'preferences', | ||
}, | ||
}, | ||
}, | ||
{ | ||
persistOptions: { | ||
persister: sessionStoragePersister, | ||
dehydrateOptions: { | ||
shouldDehydrateQuery: (query) => | ||
query.state.status === 'success' && | ||
query.queryKey[0] === 'session', | ||
}, | ||
}, | ||
}, | ||
]), | ||
), | ||
], | ||
} |
75 changes: 75 additions & 0 deletions
75
examples/angular/multiple-persisters/src/app/components/session-data.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { Component, inject } from '@angular/core' | ||
import { injectQuery } from '@tanstack/angular-query-experimental' | ||
import { HttpClient } from '@angular/common/http' | ||
import { firstValueFrom } from 'rxjs' | ||
import { DatePipe } from '@angular/common' | ||
|
||
interface SessionData { | ||
lastActive: string | ||
currentView: string | ||
activeFilters: Array<string> | ||
temporaryNotes: string | ||
} | ||
|
||
@Component({ | ||
selector: 'session-data', | ||
template: ` | ||
@if (sessionData.isLoading()) { | ||
<div class="animate-pulse p-6 bg-white rounded-lg shadow-md"> | ||
<div class="h-4 bg-gray-200 rounded w-3/4 mb-4"></div> | ||
<div class="h-4 bg-gray-200 rounded w-1/2"></div> | ||
</div> | ||
} @else if (sessionData.isError()) { | ||
<div class="p-6 bg-red-50 rounded-lg shadow-md text-red-600"> | ||
Error loading session data: {{ sessionData.error() }} | ||
</div> | ||
} @else { | ||
<div class="p-6 bg-white rounded-lg shadow-md"> | ||
<div class="flex items-center gap-2 mb-4"> | ||
🔑 | ||
<h2 class="text-xl font-semibold"> | ||
Session Data | ||
<span class="italic text-sm">(stored in sessionStorage)</span> | ||
</h2> | ||
</div> | ||
<div class="space-y-3"> | ||
<div class="flex justify-between"> | ||
<span class="text-gray-600">Last Active:</span> | ||
<span class="font-medium"> | ||
{{ sessionData.data()?.lastActive | date }} | ||
</span> | ||
</div> | ||
<div class="flex justify-between"> | ||
<span class="text-gray-600">Current View:</span> | ||
<span class="font-medium">{{ | ||
sessionData.data()?.currentView | ||
}}</span> | ||
</div> | ||
<div class="flex justify-between"> | ||
<span class="text-gray-600">Active Filters:</span> | ||
<span class="font-medium"> | ||
{{ sessionData.data()?.activeFilters?.join(', ') }} | ||
</span> | ||
</div> | ||
<div class="flex justify-between"> | ||
<span class="text-gray-600">Temporary Notes:</span> | ||
<span class="font-medium">{{ | ||
sessionData.data()?.temporaryNotes | ||
}}</span> | ||
</div> | ||
</div> | ||
</div> | ||
} | ||
`, | ||
standalone: true, | ||
imports: [DatePipe], | ||
}) | ||
export class SessionDataComponent { | ||
#http = inject(HttpClient) | ||
|
||
sessionData = injectQuery(() => ({ | ||
queryKey: ['session'], | ||
queryFn: () => firstValueFrom(this.#http.get<SessionData>('/session')), | ||
staleTime: 1000 * 60 * 60, // 1 hour | ||
})) | ||
} |
73 changes: 73 additions & 0 deletions
73
examples/angular/multiple-persisters/src/app/components/user-preferences.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { Component, inject } from '@angular/core' | ||
import { injectQuery } from '@tanstack/angular-query-experimental' | ||
import { HttpClient } from '@angular/common/http' | ||
import { firstValueFrom } from 'rxjs' | ||
|
||
interface UserPreferences { | ||
theme: string | ||
language: string | ||
notifications: boolean | ||
fontSize: string | ||
} | ||
|
||
@Component({ | ||
selector: 'user-preferences', | ||
template: ` | ||
@if (userPreferences.isLoading()) { | ||
<div class="animate-pulse p-6 bg-white rounded-lg shadow-md"> | ||
<div class="h-4 bg-gray-200 rounded w-3/4 mb-4"></div> | ||
<div class="h-4 bg-gray-200 rounded w-1/2"></div> | ||
</div> | ||
} @else if (userPreferences.isError()) { | ||
<div class="p-6 bg-red-50 rounded-lg shadow-md text-red-600"> | ||
Error loading preferences: {{ userPreferences.error() }} | ||
</div> | ||
} @else { | ||
<div class="p-6 bg-white rounded-lg shadow-md"> | ||
<div class="flex items-center gap-2 mb-4"> | ||
⚙️ | ||
<h2 class="text-xl font-semibold"> | ||
User Preferences | ||
<span class="italic text-sm">(stored in localStorage)</span> | ||
</h2> | ||
</div> | ||
<div class="space-y-3"> | ||
<div class="flex justify-between"> | ||
<span class="text-gray-600">Theme:</span> | ||
<span class="font-medium">{{ userPreferences.data()?.theme }}</span> | ||
</div> | ||
<div class="flex justify-between"> | ||
<span class="text-gray-600">Language:</span> | ||
<span class="font-medium">{{ | ||
userPreferences.data()?.language | ||
}}</span> | ||
</div> | ||
<div class="flex justify-between"> | ||
<span class="text-gray-600">Notifications:</span> | ||
<span class="font-medium">{{ | ||
userPreferences.data()?.notifications ? 'Enabled' : 'Disabled' | ||
}}</span> | ||
</div> | ||
<div class="flex justify-between"> | ||
<span class="text-gray-600">Font Size:</span> | ||
<span class="font-medium">{{ | ||
userPreferences.data()?.fontSize | ||
}}</span> | ||
</div> | ||
</div> | ||
</div> | ||
} | ||
`, | ||
standalone: true, | ||
imports: [], | ||
}) | ||
export class UserPreferencesComponent { | ||
#http = inject(HttpClient) | ||
|
||
userPreferences = injectQuery(() => ({ | ||
queryKey: ['preferences'], | ||
queryFn: () => | ||
firstValueFrom(this.#http.get<UserPreferences>('/preferences')), | ||
staleTime: 1000 * 60 * 60, // 1 hour | ||
})) | ||
} |
Oops, something went wrong.