Using blinkDB in React is not much different from using blinkDB without a framework - You can create tables, register hooks, and use all of the CRUD functions the same way you use them in normal Typescript.
Nevertheless, the @blinkdb/react
package provides
tools to make blinkDB easier to use in React.
To do CRUD operations in components, you need the database tables on which these operations
are performed. In React, @blinkdb/react
offers you a typesafe method to pass down the database & the
related tables using context.
This system of passing down tables using context is only one way of doing it. Of course, you can use any other methods to make tables available to children instead, like a state management library.
To make sure that you can access tables in a typesafe way, you need to create a model.
import { createTable } from 'blinkdb';
import { ModelOf, ValidModel } from '@blinkdb/react';
// ---
// First, create an object that holds all your tables
// ---
export const model = (db) => ({
users: createTable<User>(db, "users")(),
// Nested tables work too!
nested: {
posts: createTable<Post>(db, "posts")(),
images: createTable<PostImages>(db, "postImages")()
}
}) satisfies ValidModel;
// ---
// Use `ModelOf` to create a typesafe representation
// of your database tables - You'll be using this
// to access the tables later!
// ---
export type Model = ModelOf<typeof model>;
You can then wrap your App with the BlinkDbProvider
component.
It works like a common React Context
which passes the db & model to wrapped components.
import { createDB } from 'blinkdb';
import { BlinkDbProvider } from '@blinkdb/react';
import { model } from './model.ts';
// Wrap your App in BlinkDbProvider!
export const App = () => {
return (
<BlinkDbProvider db={createDB()} model={model}>
...
</BlinkDbProvider>
)
}
To retrieve a specific database table, perhaps for inserting items or querying items,
you can use the useTable()
hook.
import { useTable } from '@blinkdb/react';
import { Model } from './model.ts';
const Component = () => {
const userTable = useTable((model: Model) => model.users);
const postTable = useTable((model: Model) => model.nested.posts);
...
}
If you want to use the database instance in an component, you can use the useDB()
hook.
import { useDB } from '@blinkdb/react';
const Component = () => {
const db = useDB();
...
}
The blinkdb
package already provides many ways to retrieve entities from tables.
In React, you can use the useFirst()
, useMany()
and useOne()
hooks to retrieve entities from the database instead.
Because they take advantage of the way React re-renders components, these hooks are more performant than their TS counterparts.
import { useTable, useFirst, useMany, useOne } from '@blinkdb/react';
import { Model } from './model.ts';
const Component = () => {
const userTable = useTable((model: Model) => model.users);
// Retrieve first user called Bob
const { data: bob } = useFirst(userTable, {
where: {
name: "Bob"
}
});
// Retrieve all users older than 87
const { data: oldUsers } = useMany(userTable, {
where: {
age: { gte: 87 }
}
});
// Retrieve alice by uuid
const { data: alice } = useOne(userTable, 'alice-uuid');
...
}
Because queries don’t finish running immediately, the object returned from these hooks tracks if items have been retrieved yet, and the current state of the query.
import { useTable, useOne } from '@blinkdb/react';
import { Model } from './model.ts';
const Component = () => {
const userTable = useTable((model: Model) => model.users);
const { data: alice, error, state } = useOne(userTable, 'alice-uuid');
return (
<>
{error && <span>ERROR: {error}</span>}
{state === "loading" && <span>Loading user...</span>}
{alice && (
<UserCard user={alice} />
)}
</>
);
}
The object returned from the queries is of type QueryResult<T>
, and looks like this:
type QueryResult<T> {
// Retrieved data if the query has loaded items
data: T|undefined;
// An error object if the query has produced an error
error: Error|undefined;
// The current state of the query
state: "loading"|"done"|"error";
}