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

@altrx/gundb-react-hooks

v1.0.0-rc3

Published

Type-safe, performant GunDB hooks for React/Preact with authentication, error handling, and debugging utilities

Downloads

106

Readme

GunDB React Hooks

npm version TypeScript License: MIT

Type-safe, performant GunDB hooks for React/Preact with comprehensive error handling, loading states, and debugging utilities.

Features

  • Type-safe - Comprehensive TypeScript definitions
  • Performant - Optimized with memoization and proper cleanup
  • Reliable - Built-in error handling and loading states
  • Developer-friendly - Debug utilities and development warnings
  • Zero memory leaks - Proper listener cleanup and memory management
  • React & Preact - Support for both frameworks
  • Real-time - Live updates with efficient debouncing
  • Authentication - Built-in auth provider with key management and storage
  • Pagination - High-performance paginated collections with smart caching

Quick Start

Installing

npm install @altrx/gundb-react-hooks
# or
yarn add @altrx/gundb-react-hooks
# or
pnpm add @altrx/gundb-react-hooks

Basic Usage

import React from 'react';
import Gun from 'gun';
import { useGun, useGunState, useGunCollectionState } from '@altrx/gundb-react-hooks';

function App() {
  const gun = useGun(Gun, { peers: ['http://localhost:8765/gun'] });

  return <UserProfile gun={gun} />;
}

function UserProfile({ gun }) {
  const {
    fields: profile,
    put,
    error,
    isLoading
  } = useGunState(gun.get('user').get('profile'));

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.err}</div>;

  return (
    <div>
      <h1>{profile.name || 'Anonymous'}</h1>
      <button onClick={() => put({ name: 'John Doe' })}>
        Update Name
      </button>
    </div>
  );
}

With Authentication

import { AuthProvider, useAuth } from '@altrx/gundb-react-hooks';

function App() {
  return (
    <AuthProvider
      Gun={Gun}
      sea={Gun.SEA}
      storage={localStorage}
      gunOpts={{ peers: ['http://localhost:8765/gun'] }}
    >
      <AuthenticatedApp />
    </AuthProvider>
  );
}

function AuthenticatedApp() {
  const { user, login, logout, isLoggedIn, appKeys } = useAuth();

  const { fields: profile, put } = useGunState(
    user?.get('profile'),
    { appKeys }
  );

  if (!isLoggedIn) {
    return (
      <div>
        <button onClick={() => login()}>Login</button>
      </div>
    );
  }

  return (
    <div>
      <h1>Welcome, {profile.name || 'User'}!</h1>
      <input
        value={profile.name || ''}
        onChange={(e) => put({ name: e.target.value })}
        placeholder="Enter your name"
      />
      <button onClick={() => logout()}>Logout</button>
    </div>
  );
}

With Error Handling & TypeScript

interface UserProfile {
  name: string;
  email: string;
  avatar?: string;
}

interface TodoItem {
  text: string;
  completed: boolean;
  createdAt: string;
}

function TypeSafeApp() {
  const gun = useGun(Gun, { peers: ['http://localhost:8765/gun'] });

  // Type-safe user profile
  const {
    fields: profile,
    put: updateProfile,
    error: profileError,
    isLoading: profileLoading
  } = useGunState<UserProfile>(gun.get('user').get('profile'));

  // Type-safe todo collection with pagination
  const {
    currentPageItems: todos,
    addToSet: addTodo,
    removeFromSet: removeTodo,
    updateInSet: updateTodo,
    error: todosError,
    totalItems: todoCount,
    currentPage,
    totalPages,
    nextPage,
    prevPage,
    pageSize,
    setPageSize
  } = useGunCollectionStatePaginated<TodoItem>(gun.get('todos'), {
    pageSize: 10,
    sortBy: 'createdAt',
    sortOrder: 'desc',
    preloadPages: 1
  });

  const handleAddTodo = async () => {
    try {
      await addTodo({
        text: 'New todo',
        completed: false,
        createdAt: new Date().toISOString()
      });
    } catch (error) {
      console.error('Failed to add todo:', error);
    }
  };

  if (profileError || todosError) {
    return <ErrorComponent error={profileError || todosError} />;
  }

  return (
    <div>
      <h1>{profile.name}'s Todos ({todoCount})</h1>

      {/* Pagination Controls */}
      <div>
        <span>Page {currentPage + 1} of {totalPages}</span>
        <select value={pageSize} onChange={(e) => setPageSize(Number(e.target.value))}>
          <option value={5}>5 per page</option>
          <option value={10}>10 per page</option>
          <option value={20}>20 per page</option>
        </select>
      </div>

      {/* Todo Items */}
      {todos.map(todo => (
        <TodoItem
          key={todo.nodeID}
          todo={todo}
          onToggle={() => updateTodo(todo.nodeID, { completed: !todo.completed })}
          onRemove={() => removeTodo(todo.nodeID)}
        />
      ))}

      {/* Pagination Navigation */}
      <div>
        <button onClick={prevPage} disabled={currentPage === 0}>
          Previous
        </button>
        <button onClick={nextPage} disabled={currentPage >= totalPages - 1}>
          Next
        </button>
      </div>

      <button onClick={handleAddTodo}>Add Todo</button>
    </div>
  );
}

API Reference

API Reference

Core Hooks

useGun(Gun, options)

Initialize a Gun instance.

const gun = useGun(Gun, {
  peers: ['http://localhost:8765/gun'],
  localStorage: true,
});

useGunState<T>(ref, options)

Manage state for a Gun node with error handling and loading states.

const {
  fields, // T: The current state
  put, // (data: Partial<T>) => Promise<void>
  remove, // (field: string) => Promise<void>
  error, // GunError | null
  isLoading, // boolean
  isConnected, // boolean
} = useGunState<T>(ref, options);

useGunCollectionState<T>(ref, options)

Manage collections (Sets) with comprehensive CRUD operations.

const {
  collection, // Map<string, NodeT<T>>
  items, // NodeT<T>[] - Array for easy iteration
  addToSet, // (data: T, nodeID?: string) => Promise<void>
  updateInSet, // (nodeID: string, data: Partial<T>) => Promise<void>
  removeFromSet, // (nodeID: string) => Promise<void>
  error, // GunError | null
  isLoading, // boolean
  count, // number
} = useGunCollectionState<T>(ref, options);

useGunCollectionStatePaginated<T>(ref, options)

High-performance paginated collections with smart caching and real-time updates.

const {
  currentPageItems, // NodeT<T>[] - Current page items
  currentPage, // number - Current page index (0-based)
  totalPages, // number - Total number of pages
  pageSize, // number - Items per page
  setPageSize, // (size: number) => void
  nextPage, // () => void
  prevPage, // () => void
  goToPage, // (page: number) => void
  hasNextPage, // boolean
  hasPrevPage, // boolean
  isLoadingPage, // boolean
  totalItems, // number - Total items in collection
  // ... all useGunCollectionState methods
  addToSet, // (data: T, nodeID?: string) => Promise<void>
  updateInSet, // (nodeID: string, data: Partial<T>) => Promise<void>
  removeFromSet, // (nodeID: string) => Promise<void>
  error, // GunError | null
  preloadedPages, // Set<number> - Cached pages
} = useGunCollectionStatePaginated<T>(ref, options);

useGunKeyAuth(gun, keys, triggerAuth?)

Handle authentication with key pairs.

const [
  namespacedGraph, // IGunUserReference
  isLoggedIn, // boolean
  authError, // GunError | null
] = useGunKeyAuth(gun, keyPair, true);

useGunKeys(sea, existingKeys?)

Generate or use existing key pairs.

const keyPair = useGunKeys(SEA, existingKeys);

Utility Hooks

useGunDebug(ref, label, enabled?)

Debug hook for development - logs all updates.

// Only active in development
useGunDebug(userRef, 'UserProfile', process.env.NODE_ENV === 'development');

useGunConnection(ref)

Monitor connection status and health.

const { isConnected, lastSeen, error } = useGunConnection(gun);

Context Providers

GunProvider

Provide Gun instance through React context.

<GunProvider gun={Gun} options={{ peers: ['http://localhost:8765/gun'] }}>
  <App />
</GunProvider>

useGunContext()

Access Gun instance from context.

const gun = useGunContext();

AuthProvider

Comprehensive authentication provider with key management.

<AuthProvider
  Gun={Gun}
  sea={Gun.SEA}
  storage={localStorage}
  gunOpts={{ peers: ['http://localhost:8765/gun'] }}
>
  <App />
</AuthProvider>

useAuth()

Access authentication state and methods.

const {
  user, // IGunUserReference
  login, // (keys?: KeyPair) => void
  logout, // (callback?: () => void) => void
  isLoggedIn, // boolean
  appKeys, // KeyPair | undefined
  gun, // IGunChainReference
} = useAuth();

Types

interface GunError {
  err: string;
  code?: string | number;
  context?: string;
}

interface NodeData<T> {
  nodeID: string;
  // ... your data
}

interface UseGunStateReturn<T> {
  fields: T;
  put: (data: Partial<T>) => Promise<void>;
  remove: (field: string) => Promise<void>;
  error: GunError | null;
  isLoading: boolean;
  isConnected: boolean;
}

Advanced Usage

Error Handling Patterns

function MyComponent() {
  const { fields, put, error } = useGunState(ref);

  // Global error handling
  if (error) {
    return <ErrorBoundary error={error} />;
  }

  // Operation-specific error handling
  const handleSave = async () => {
    try {
      await put(data);
      showSuccessMessage();
    } catch (error) {
      showErrorMessage(error.err);
    }
  };
}

Development Debugging

function DebuggedComponent() {
  const gun = useGunContext();
  const userRef = gun.user().get('profile');

  // Debug all updates in development
  useGunDebug(userRef, 'UserProfile');

  const { fields } = useGunState(userRef);
  return <div>{fields.name}</div>;
}

Performance Optimization

// Memoize expensive operations
const expensiveData = useMemo(() => {
  return items
    .filter((item) => item.category === selectedCategory)
    .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
}, [items, selectedCategory]);

// Use callback for event handlers
const handleAddItem = useCallback(
  async (item) => {
    await addToSet(item);
  },
  [addToSet],
);

Migration from v0.9.x

New Pagination Hook

v1.0.0 introduces useGunCollectionStatePaginated for high-performance collection management:

// Before: Basic collection
const { items, addToSet } = useGunCollectionState(ref);

// After: Paginated with optimization
const { currentPageItems, addToSet, nextPage, totalPages } =
  useGunCollectionStatePaginated(ref, {
    pageSize: 20,
    sortBy: 'createdAt',
    preloadPages: 2,
  });

Performance Benefits

  • Memory Efficient: Only loads current page + preloaded pages
  • Smart Caching: 5-minute page cache with automatic invalidation
  • Real-time Updates: Debounced live synchronization
  • Type Safety: Full TypeScript support with inference

For detailed migration instructions and compatibility information, see the detailed documentation for each hook.

Development & Testing

Debug Mode

// Enable debug logging for specific components
useGunDebug(ref, 'ComponentName', true);

// Connection monitoring
const { isConnected, lastSeen } = useGunConnection(gun);

Error Boundaries

function AppWithErrorBoundary() {
  return (
    <ErrorBoundary>
      <GunProvider gun={Gun} options={opts}>
        <App />
      </GunProvider>
    </ErrorBoundary>
  );
}

Examples & Documentation

Contributing

We welcome contributions! Please see our contributing guidelines and:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for your changes
  4. Ensure type safety with TypeScript
  5. Submit a pull request

License

Licensed under MIT.

Acknowledgments