Skip to content

Commit c513df0

Browse files
Add notes about query subscriptions to READMEs
1 parent 822d8f0 commit c513df0

File tree

3 files changed

+99
-3
lines changed

3 files changed

+99
-3
lines changed

packages/common/src/client/watched/WatchedQuery.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export interface WatchedQueryOptions {
6161
reportFetching?: boolean;
6262

6363
/**
64-
* By default, watched queries requery the database on any change to any dependant table of the query.
64+
* By default, watched queries requery the database on any change to any dependent table of the query.
6565
* Supplying an override here can be used to limit the tables which trigger querying the database.
6666
*/
6767
triggerOnTables?: string[];

packages/react/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,28 @@ function MyWidget() {
391391
)
392392
}
393393
```
394+
395+
## Query Subscriptions
396+
397+
The `useWatchedQuerySubscription` hook lets you access the state of an externally managed `WatchedQuery` instance. Managing a query outside of a component enables in-memory caching and sharing of results between multiple subscribers. This reduces async loading time during component mount (thanks to in-memory caching) and minimizes the number of SQLite queries (by sharing results between multiple components).
398+
399+
```jsx
400+
// The lifecycle of this query is managed outside of any individual React component.
401+
// The data is kept up-to-date in the background and can be shared by multiple subscribers.
402+
const listsQuery = powerSync.query({ sql: 'SELECT * FROM lists' }).differentialWatch();
403+
404+
export const ContentComponent = () => {
405+
// Subscribes to the `listsQuery` instance. The subscription is automatically
406+
// cleaned up when the component unmounts. The `data` value always reflects
407+
// the latest state of the query.
408+
const { data: lists } = useWatchedQuerySubscription(listsQuery);
409+
410+
return (
411+
<View>
412+
{lists.map((l) => (
413+
<Text key={l.id}>{JSON.stringify(l)}</Text>
414+
))}
415+
</View>
416+
);
417+
};
418+
```

packages/vue/README.md

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,78 @@ const addList = () => {
101101
</template>
102102
```
103103

104-
### Static query
104+
### Incremental Query
105+
106+
By default, the `useQuery` composable emits a new `data` reference whenever any change occurs in the query's dependent tables. With incremental queries, updates are only emitted when relevant changes are detected, and the internal `data` array preserves object references for unchanged rows between emissions. This helps prevent unnecessary re-renders in your components.
107+
108+
````Vue
109+
// TodoListDisplayQuery.vue
110+
<script setup>
111+
import { usePowerSync, useQuery } from '@powersync/vue';
112+
import { ref } from 'vue';
113+
114+
const { data: lists, isLoading, isFetching, error} = useQuery('SELECT * FROM lists', [], {
115+
rowComparator: {
116+
keyBy: item => item.id,
117+
compareBy: item => JSON.stringify(item)
118+
}
119+
});
120+
</script>
121+
122+
<template>
123+
<input v-model="query" />
124+
<div v-if="isLoading">Loading...</div>
125+
<div v-else-if="isFetching">Updating results...</div>
126+
127+
<div v-if="error">{{ error }}</div>
128+
<ul v-else>
129+
<li v-for="l in lists" :key="l.id">{{ l.name }}</li>
130+
</ul>
131+
</template>
132+
133+
### Query Subscriptions
134+
135+
The `useWatchedQuerySubscription` composable lets you access the state of an externally managed `WatchedQuery` instance. To enable in-memory caching and sharing of results between multiple subscribers, the query should be created outside of any component—such as in a module or singleton. This reduces async loading time when components mount (thanks to in-memory caching) and minimizes the number of SQLite queries (by sharing results between components).
136+
137+
```js
138+
// listsQuery.js
139+
import { usePowerSync } from '@powersync/vue';
140+
141+
// This module creates and exports a single shared query instance.
142+
// It should be imported wherever you want to subscribe to the query.
143+
let listsQuery;
144+
export function getListsQuery() {
145+
if (!listsQuery) {
146+
// Note: usePowerSync() must be called in a Vue setup context, so you may need to
147+
// pass the PowerSync instance here if you are not using the default context.
148+
const powerSync = usePowerSync();
149+
listsQuery = powerSync.value.query({ sql: 'SELECT * FROM lists' }).differentialWatch();
150+
}
151+
return listsQuery;
152+
}
153+
```
154+
155+
```vue
156+
<!-- ContentComponent.vue -->
157+
<script setup>
158+
import { useWatchedQuerySubscription } from '@powersync/vue';
159+
import { getListsQuery } from './listsQuery';
160+
161+
// Subscribe to the shared `listsQuery` instance. The subscription is automatically
162+
// cleaned up when the component unmounts. The `data` value always reflects
163+
// the latest state of the query.
164+
const { data: lists } = useWatchedQuerySubscription(getListsQuery());
165+
</script>
166+
167+
<template>
168+
<ul>
169+
<li v-for="l in lists" :key="l.id">{{ l.name }} ({{ l.id }})</li>
170+
</ul>
171+
</template>
172+
```
173+
174+
175+
### Static Query
105176
106177
The `useQuery` composable can be configured to only execute initially and not every time changes to dependent tables are detected. The query can be manually re-executed by using the returned `refresh` function.
107178
@@ -122,7 +193,7 @@ const { data: list, refresh } = useQuery('SELECT id, name FROM lists', [], {
122193
<button @click="refresh">Refresh list</button>
123194
</template>
124195
125-
```
196+
````
126197

127198
### TypeScript Support
128199

0 commit comments

Comments
 (0)