npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@taladb/react

v0.11.8

Published

React hooks for TalaDB — useFind, useFindOne, and useCollection for React and React Native

Readme

@taladb/react

React and React Native hooks for TalaDB — live queries that re-render your components when the local database changes.

npm License: Apache 2.0

What this gives you

TalaDB collections are already reactive — col.subscribe(filter, cb) pushes a fresh snapshot on every matching change. These hooks wire that into React's rendering model for you: subscription lifecycle, snapshot identity, and cleanup, so a write in one component re-renders every other component reading the same data.

Reads are backed by useSyncExternalStore, so snapshots never tear under concurrent rendering.

import { TalaDBProvider, useCollection, useFind, useWrite } from '@taladb/react'

function App() {
  return (
    <TalaDBProvider name="myapp.db" fallback={<Spinner />}>
      <Articles />
    </TalaDBProvider>
  )
}

function Articles() {
  const articles = useCollection<Article>('articles')
  const { data, loading } = useFind(articles, { published: true })
  const { write, pending } = useWrite<Article>({ collection: 'articles' })

  if (loading) return <Spinner />

  return (
    <>
      {data.map((a) => (
        <h2 key={a._id}>{a.title}</h2>
      ))}
      <button
        disabled={pending}
        onClick={() => write({ type: 'insert', doc: { title: 'New', published: false } })}
      >
        Add
      </button>
    </>
  )
}

There is no cache to invalidate and no refetch to trigger. The write commits locally and the list above re-renders.

Installation

pnpm add @taladb/react taladb

Plus the platform backend TalaDB needs — @taladb/web in the browser, @taladb/react-native on device, @taladb/node on the server. See the taladb package.

Peer dependencies: react >= 18, taladb ^0.11.0.

Provider

TalaDBProvider takes one of two shapes.

Provider-owned — pass a name and it owns the openDB lifecycle: opens lazily on the client, never during SSR, and closes on unmount. This is the right form for Next.js.

<TalaDBProvider name="myapp.db" options={{ /* OpenDBOptions */ }} fallback={<Spinner />}>

Children render only once the database is ready, so useTalaDB() never observes a missing instance. fallback renders until then (and during SSR); it defaults to null.

Caller-owned — pass a db you opened yourself, and you keep the lifecycle.

const db = await openDB('myapp.db')
<TalaDBProvider db={db}>

Registering collection options

Per-collection options (schema, syncSchema, migrateDocument, …) belong on the provider, keyed by collection name:

<TalaDBProvider
  name="myapp.db"
  collections={{
    articles: { schema: ArticleSchema, syncSchema: { version: 1 } },
  }}
>

This matters: without the registry, useCollection resolves a bare db.collection(name) handle, and writes through useWrite silently skip schema validation and the _v shape stamp. The registry is read when a handle is first created and treated as static, so an inline object here won't thrash live queries.

Hooks

useCollection<T>(name, options?)

Resolves a collection from the provider's database, applying the registered options for name. The handle is memoized — same reference every render unless the db or name changes — so pass it straight to useFind without wrapping in useMemo. A per-call options argument overrides the registry entry.

const articles = useCollection<Article>('articles')

useFind<T>(collection, filter?)

Subscribes to a live query.

const { data, loading, error } = useFind(articles, { locale: 'en' })

| Field | Type | | |---|---|---| | data | T[] | Matching documents. Empty while loading. | | loading | boolean | True until the first snapshot arrives. | | error | unknown \| null | Last subscription error, cleared by the next good snapshot. |

Inline filter objects are safe — the filter is serialized for subscription identity, so { active: true } on every render does not re-subscribe.

useFindOne<T>(collection, filter)

Same, for a single document. data is T | null — null both while loading and when nothing matched.

const { data: article, loading } = useFindOne(articles, { slug })

useAggregate<T, R>(collection, pipeline)

A live aggregation, and the paging primitive — find() has no sort, skip, or limit, so reach for this when you need them.

const { data, loading } = useAggregate<Article>(articles, [
  { $match: { published: true } },
  { $sort: { createdAt: -1 } },
  { $skip: page * 20 },
  { $limit: 20 },
])

Inline pipeline arrays are serialized for identity, the same as filters.

useWrite<T>({ collection })

Writes to a collection. The write is local, immediate, and durable — every useFind / useFindOne / useAggregate on that collection re-renders once it commits.

const { write, writeAsync, pending, error } = useWrite<Article>({ collection: 'articles' })

write({ type: 'insert', doc: { title: 'Hello', published: false } })
write({ type: 'update', where: { _id: id }, set: { published: true } })
write({ type: 'delete', where: { _id: id } })

await writeAsync({ type: 'insert', doc })  // rejects on error

write is fire-and-forget — failures land on error rather than being thrown into render. writeAsync resolves once the write commits and rejects on failure. pending is true while a write is in flight.

It's named useWrite, not useMutation, because that's all it is: a local write with no network step and no rollback to reason about. The database is on the device — the write either committed or threw.

useTalaDB()

The TalaDB instance from the nearest provider, for anything the hooks above don't cover.

Server rendering

openDB cannot run during server rendering. Use the provider-owned form (name=), which opens only on the client and renders fallback until the handle exists. Hooks below it never see a null database.

@taladb/react/query

A subpath export for a local-first data layer over TalaDB — cache-as-a-real-collection, background revalidation, writes that drain to the network without blocking the UI.

Status: in progress. The type surface, defineBackend, and the envelope and query-record layer are in place. The hooks are not implemented yet — don't build on it.

Documentation

https://taladb.dev

License

Apache 2.0 © TalaDB