Live Queries
Description - Couchbase Lite Live Query Concepts Related Content - SQL++ for Mobile
Activating a Live Query
A live query is a query that, once activated, remains active and monitors the database for changes; refreshing the result set whenever a change occurs. As such, it is a great way to build reactive user interfaces - especially table/list views - that keep themselves up to date.
So, a simple use case may be: A replicator running and pulling new data from a server, whilst a live-query-driven UI automatically updates to show the data without the user having to manually refresh. This helps your app feel quick and responsive.
With Couchbase Lite for React Native, live queries can be watched through:
* Listener callbacks: `Query.addChangeListener`
Each time you start watching a live query, the query is executed and an initial change notification is dispatched. The query is then kept active and further change notifications are dispatched whenever a change occurs.
Example 1. Starting a Live Query - Change Listener
import { ListenerToken } from '@couchbase/couchbase-lite-react-native';
// Register a change listener
const token: ListenerToken = await query.addChangeListener((change) => {
if (change.error) {
console.error('Query error:', change.error);
return;
}
const results = change.results;
// results is an array of result objects
for (const doc of results) {
console.log('Result:', doc);
}
});
|
Version 1.0
Change listeners now return a |
|
Version 1.1
Live query listeners use the TurboModule typed event path on New Architecture builds. This improves listener routing and cleanup consistency across iOS and Android. |
Example 2. Stopping a Live Query - Change Listener
// Remove listener using new API
await token.remove();
|
Deprecated
The
|
Query Change Data Structure
When a query result changes, your callback receives a QueryChange object:
interface QueryChange {
error: string; // Error message if query failed
query: Query; // Reference to the query
results: ResultSet; // Array of result objects
}
Example 3. Complete Live Query with Error Handling
import { ListenerToken } from '@couchbase/couchbase-lite-react-native';
const query = database.createQuery(
'SELECT META().id, name, email FROM _default.users WHERE isActive = true'
);
const token: ListenerToken = await query.addChangeListener((change) => {
if (change.error) {
console.error('Query error:', change.error);
return;
}
console.log(`Found ${change.results.length} active users`);
change.results.forEach(result => {
console.log(`User: ${result.name} - ${result.email}`);
});
});
// Remove when done
await token.remove();
Example 4. React Hook Pattern for Live Queries
import { useEffect, useState } from 'react';
import { ListenerToken } from '@couchbase/couchbase-lite-react-native';
function ActiveUsersScreen({ database }) {
const [users, setUsers] = useState([]);
useEffect(() => {
if (!database) return;
let token;
const setup = async () => {
const query = database.createQuery(
'SELECT META().id, name FROM _default.users WHERE isActive = true'
);
token = await query.addChangeListener((change) => {
if (!change.error) {
setUsers(change.results);
}
});
};
setup();
// Cleanup on unmount
return () => {
if (token && !token.isRemoved()) {
token.remove();
}
};
}, [database]);
return (
// Render users list
);
}
Best Practices
Always Remove Listeners
In React components, use the cleanup function to prevent memory leaks:
useEffect(() => {
let token;
const setup = async () => {
token = await query.addChangeListener((change) => {
// Handle changes
});
};
setup();
return () => {
if (token && !token.isRemoved()) {
token.remove();
}
};
}, [query]);
Check Before Removing
if (!token.isRemoved()) {
await token.remove();
}