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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@vaultrice/react

v1.1.0

Published

<!-- [![Tests](https://github.com/vaultrice/react/workflows/node/badge.svg)](https://github.com/vaultrice/react/actions?query=workflow%3Anode) --> [![npm version](https://img.shields.io/npm/v/@vaultrice/react.svg?style=flat-square)](https://www.npmjs.com/

Downloads

40

Readme

Vaultrice React SDK

npm version

A set of React hooks and utilities for building real-time, offline-first, and optionally end-to-end encrypted applications using Vaultrice NonLocalStorage.
Under the hood, @vaultrice/react uses @vaultrice/sdk for all storage, sync, and presence features.

Vaultrice is ideal for collaborative apps, cross-device sync, and privacy-sensitive use cases—without custom backend infrastructure.


Table of Contents

  1. Features
  2. Installation
  3. Quick Start
  4. Core Hooks
  5. Atomic Operations
  6. Examples
  7. Helpers
  8. Related Packages

Features

  • Offline-first: Local queueing and automatic sync when online.
  • Real-time presence & messaging: Built-in WebSocket support for live updates and user presence.
  • End-to-end encryption: Optional client-side encryption for sensitive data.
  • Cross-device sync: Seamless state sharing across browsers and devices.
  • TTL & metadata: Per-key expiration and rich metadata.
  • Atomic operations: Server-side atomic operations for counters, arrays, and objects.
  • Easy integration: Simple React hooks for state, counters, messaging, and more.

Installation

npm install @vaultrice/react

Quick Start

import { useNonLocalState } from '@vaultrice/react'

const [value, setValue, error] = useNonLocalState<string>('myRoom', 'myKey', {
  credentials: {
    projectId: 'YOUR_PROJECT_ID',
    apiKey: 'YOUR_API_KEY',
    apiSecret: 'YOUR_API_SECRET'
  }
})

// Use value in your UI, update with setValue(newValue)

Core Hooks

Basic State Management

  • useNonLocalState – Manage a single value with real-time sync.
  • useMultiNonLocalStates – Manage multiple keys atomically.

Specialized Hooks

  • useNonLocalCounter – Atomic increment/decrement for counters.
  • useNonLocalArray – Array management with atomic push and splice operations.
  • useNonLocalObject – Object management with merge and nested operations.
  • useNonLocalGeneralState – General state with all atomic operations available.

Communication

  • useMessaging – Real-time messaging and presence.

Utilities

  • createNonLocalStore – Simple fetch/post API for a single key, e.g., to be used with TanStack Query.

Atomic Operations

The SDK provides powerful atomic operations that are executed server-side, preventing race conditions:

Counter Operations

import { useNonLocalCounter } from '@vaultrice/react'

const [count, increment, decrement, error] = useNonLocalCounter('roomId', 'counterKey', { 
  credentials: { ... } 
})

// Increment by 1 (default)
await increment()

// Increment by specific amount
await increment(5)

// Decrement by 1 (default)
await decrement()

// Decrement by specific amount
await decrement(2)

Array Operations

import { useNonLocalArray } from '@vaultrice/react'

const [items, { push, splice, setArray }, error] = useNonLocalArray('roomId', 'listKey', { 
  credentials: { ... } 
})

// Atomically append to array
await push('new item')

// Splice examples — atomically remove/insert/replace elements:
// Remove 1 item at index 2
await splice(2, 1)

// Insert items at index 1 without deleting
await splice(1, 0, ['inserted'])

// Replace 2 items starting at index 0 with new items
await splice(0, 2, ['a', 'b'])

// Replace entire array
await setArray(['item1', 'item2', 'item3'])

Object Operations

import { useNonLocalObject } from '@vaultrice/react'

const [user, { merge, setIn, setObject }, error] = useNonLocalObject('roomId', 'userKey', { 
  credentials: { ... } 
})

// Shallow merge into object
await merge({ name: 'John', active: true })

// Set nested value using dot notation
await setIn('profile.avatar', 'avatar.jpg')

// Replace entire object
await setObject({ name: 'John', age: 30 })

General State with All Operations

import { useNonLocalGeneralState } from '@vaultrice/react'

const [value, actions, error] = useNonLocalGeneralState('roomId', 'dataKey', { 
  credentials: { ... } 
})

// All operations available
await actions.setItem(value)
await actions.push(element)               // for arrays
// Splice via the general actions API (startIndex, deleteCount, items?)
await actions.splice(1, 0, [newItem])     // insert newItem at index 1
await actions.splice(3, 2)                // remove 2 items starting at index 3
await actions.merge(obj)                  // for objects  
await actions.setIn(path, value)          // for nested objects

Examples

Collaborative Counter

import { useNonLocalCounter } from '@vaultrice/react'

function CollaborativeCounter() {
  const [count, increment, decrement, error] = useNonLocalCounter('room1', 'counter', {
    credentials: {
      projectId: 'YOUR_PROJECT_ID',
      apiKey: 'YOUR_API_KEY',
      apiSecret: 'YOUR_API_SECRET'
    }
  })

  return (
    <div>
      <button onClick={() => increment()}>+1</button>
      <span>Count: {count}</span>
      <button onClick={() => decrement()}>-1</button>
      {error && <p>Error: {error.message}</p>}
    </div>
  )
}

Collaborative Todo List

import { useNonLocalArray } from '@vaultrice/react'

function TodoList() {
  const [todos, { push, splice }, error] = useNonLocalArray('room1', 'todos', {
    credentials: { ... }
  })

  const addTodo = (text: string) => {
    push({ id: Date.now(), text, completed: false })
  }

  return (
    <div>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>{todo.text}</li>
        ))}
      </ul>
      <button onClick={() => addTodo('New task')}>Add Todo</button>
    </div>
  )
}

User Profile Management

import { useNonLocalObject } from '@vaultrice/react'

function UserProfile() {
  const [profile, { merge, setIn }, error] = useNonLocalObject('user123', 'profile', {
    credentials: { ... }
  })

  const updateEmail = (email: string) => {
    merge({ email })
  }

  const updateProfilePicture = (url: string) => {
    setIn('profile.avatar', url)
  }

  return (
    <div>
      <h2>{profile.name}</h2>
      <p>Email: {profile.email}</p>
      <button onClick={() => updateEmail('[email protected]')}>
        Update Email
      </button>
    </div>
  )
}

Real-time Messaging

import { useMessaging } from '@vaultrice/react'

function ChatRoom() {
  const [connected, send, join, leave, getConnectionId, error] = useMessaging(
    'chatroom1',
    (message) => {
      console.log('Received:', message)
    },
    { credentials: { ... } }
  )

  useEffect(() => {
    join({ name: 'User123', avatar: 'avatar.jpg' })
    return () => leave()
  }, [])

  return (
    <div>
      <div>Connected users: {connected.length}</div>
      <button onClick={() => send({ text: 'Hello!', timestamp: Date.now() })}>
        Send Message
      </button>
    </div>
  )
}

TanStack Query Integration

import { createNonLocalStore } from '@vaultrice/react'
import { useQuery, useMutation } from '@tanstack/react-query'

const userStore = createNonLocalStore('users', 'current-user', {
  credentials: { ... }
})

function UserData() {
  const { data: user, isLoading } = useQuery({
    queryKey: ['user'],
    queryFn: userStore.fetch
  })

  const updateUser = useMutation({
    mutationFn: userStore.post
  })

  return (
    <div>
      {isLoading ? 'Loading...' : user?.value?.name}
      <button onClick={() => updateUser.mutate({ name: 'New Name' })}>
        Update
      </button>
    </div>
  )
}

Helpers

Global Credentials

You can initialize your credentials in a single place to be reused:

// e.g., in your index.ts
import { vaultrice } from '@vaultrice/react'

vaultrice.init({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY',
  apiSecret: 'YOUR_API_SECRET'
})

// in your components - credentials are automatically used
import { useNonLocalState } from '@vaultrice/react'

const [value, setValue] = useNonLocalState<string>('objectId', 'myKey')

Offline-capable NonLocalStorage

To take advantage of the offline-capable NonLocalStorage, prepare the instances before usage:

// e.g., in your index.ts
import { prepareOfflineNonLocalStorage } from '@vaultrice/react'

await prepareOfflineNonLocalStorage('objectId', credentials)

// in your components - it will automatically use the prepared offline variant
import { useNonLocalState } from '@vaultrice/react'

const [value, setValue] = useNonLocalState<string>('objectId', 'myKey')

Hook Reference

useNonLocalState

const [value, setValue, error, isLoading] = useNonLocalState<T>(id, key, options)

useNonLocalCounter

const [count, increment, decrement, error, isLoading] = useNonLocalCounter(id, key, options)

useNonLocalArray

const [array, { push, splice, setArray }, error, isLoading] = useNonLocalArray<T>(id, key, options)

useNonLocalObject

const [object, { merge, setIn, setObject }, error, isLoading] = useNonLocalObject<T>(id, key, options)

useNonLocalGeneralState

const [value, { setItem, push, splice, merge, setIn }, error, isLoading] = useNonLocalGeneralState<T>(id, key, options)

useMultiNonLocalStates

const [values, setItems, error, isLoading] = useMultiNonLocalStates(id, keys, options)

useMessaging

const [connected, send, join, leave, getConnectionId, error] = useMessaging(id, onMessage, options)

Related Packages

Support

Have questions, ideas or feedback? Open an issue or email us at [email protected]


Made with ❤️ for developers who need real-time storage, without the backend hassle.

Try Vaultrice for free!