Skip to content

Instantly share code, notes, and snippets.

@maxencehenneron
Last active March 1, 2024 20:01
Show Gist options
  • Save maxencehenneron/28e58663a96d7e2c38e0dffcc98f8673 to your computer and use it in GitHub Desktop.
Save maxencehenneron/28e58663a96d7e2c38e0dffcc98f8673 to your computer and use it in GitHub Desktop.
Defines a custom React hook useReactiveQuery that rerenders a component when the result of a SQLite query changes. It's designed to work with the drizzle-orm and expo-sqlite libraries
import { useEffect, useState } from "react";
import { AnySQLiteTable, getTableConfig } from "drizzle-orm/sqlite-core";
import { addDatabaseChangeListener } from "expo-sqlite/next";
import { SQLiteSyncRelationalQuery } from "drizzle-orm/sqlite-core/query-builders/query";
/**
* A helper hook that rerenders the component when the result of a query changes
* @param query the query to run
* @param dependencies the tables that the query depends on
* @param rowId the row id to watch for changes
* @returns the result of the query (sync)
*/
export default function useReactiveQuery<
TResult,
>(
query: SQLiteSyncRelationalQuery<TResult>,
dependencies: AnySQLiteTable[],
rowId?: TResult extends any[] ? never : number
) {
const [result, setResult] = useState<TResult>();
useEffect(() => {
setResult(query.sync());
const tableNames = dependencies.map((table) => {
return getTableConfig(table).name;
});
const subscription = addDatabaseChangeListener((change) => {
if (rowId !== undefined) {
// If the change is to the table and row we are watching
if (change.tableName === tableNames[0] && change.rowId === rowId) {
setResult(query.sync());
}
return;
}
// If the change is to a table we are watching
if (tableNames.includes(change.tableName)) {
setResult(query.sync());
}
});
return () => {
subscription.remove();
}
}, []);
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment