@channel-state/core
v0.0.5
Published
Core-library for channel-state, providing framework-agnostic, zero-dependency state management with cross-context synchronization and persistence.
Downloads
15
Maintainers
Readme
📖 Overview
@channel-state/core is the foundational package of the channel-state ecosystem. It provides the ChannelStore class, a powerful, zero-dependency solution for state management that works in any JavaScript environment. It enables seamless, real-time state synchronization across browser tabs and windows using the native BroadcastChannel and IndexedDB APIs.
🛠️ Installation
npm install @channel-state/coreyarn add @channel-state/corepnpm add @channel-state/corebun add @channel-state/core🌐 CDN Usage
For direct usage in the browser, you can use the UMD build from a CDN like jsDelivr or unpkg:
<script src="https://cdn.jsdelivr.net/npm/@channel-state/core@0"></script>🚀 Playground
Explore and experiment with channel-state in a live environment using our interactive playground.
This playground provides a simple example of how to use @channel-state/core and @channel-state/react together.
Note: To see the cross-tab state synchronization in action, open the preview in a new tab.
📚 API Reference
ChannelStore<T>
The primary class for creating and managing a synchronized state.
Constructor
new ChannelStore<T>(options: ChannelStoreOptions<T>)
| Parameter | Type | Description |
| --------- | --------------------- | ----------------------------------------------------- |
| options | ChannelStoreOptions | An object containing the configuration for the store. |
ChannelStoreOptions
| Property | Type | Required | Default | Description |
| --------- | --------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------ |
| name | string | Yes | - | A unique name for the channel. This is used for the BroadcastChannel and as the IndexedDB database name. |
| initial | T | Yes | - | The initial value of the state. |
| persist | boolean | No | false | If true, the state will be persisted to IndexedDB and restored on initialization. |
Properties
| Property | Type | Description |
| -------- | ------------- | ------------------------------------------------------------------------------- |
| status | StoreStatus | The current status of the store: 'initializing', 'ready', or 'destroyed'. |
Methods
| Method | Signature | Description |
| ------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| get() | (): T | Synchronously returns the current state. |
| set() | (value: T): void | Sets a new state, broadcasts it to other contexts, and persists it if persist is enabled. The method itself is synchronous, but persistence happens in the background. |
| subscribe() | (callback: (value: T) => void): () => void | Subscribes to state changes. The callback receives the new state. Returns an unsubscribe function. |
| subscribeStatus() | (callback: (status: StoreStatus) => void): () => void | Subscribes to store status changes. The callback receives the new status. Returns an unsubscribe function. |
| destroy() | (): void | Closes the BroadcastChannel and IndexedDB connections and cleans up all subscribers. The store instance cannot be used afterward. |
| reset() | (): Promise<void> | Resets the state to its initial value and broadcasts the change. |
🚀 Example Usage
import { ChannelStore } from '@channel-state/core'
// 1. Create a new store instance. This should be done once and shared.
const counterStore = new ChannelStore<number>({
// A unique name for the channel, used for BroadcastChannel and IndexedDB.
name: 'shared-counter',
// The initial state of the store if no persisted state is found.
initial: 0,
// Set to true to persist the state to IndexedDB.
persist: true,
})
// 2. Subscribe to status changes to know when the store is ready.
// This is crucial when `persist` is true, as it takes time to load from IndexedDB.
const unsubscribeStatus = counterStore.subscribeStatus((status) => {
console.log('Store status is now:', status)
// 3. Once the store is ready, you can safely interact with it.
if (status === 'ready') {
// Get the current state. This will be the persisted value if it exists.
const currentCount = counterStore.get()
console.log('Initial or persisted count:', currentCount)
// Set a new state. This will be broadcast to other tabs.
counterStore.set(currentCount + 1)
}
})
// 4. Subscribe to state changes from any tab.
const unsubscribeState = counterStore.subscribe((newCount) => {
console.log('Count has changed to:', newCount)
// Here you would typically update your UI.
})
// 5. It's important to clean up when your application or component unmounts.
// The function below should be called from your framework's lifecycle hook
// (e.g., `useEffect` in React, `onUnmounted` in Vue, `onDestroy` in Svelte).
function cleanup() {
unsubscribeStatus()
unsubscribeState()
counterStore.destroy()
}
// The line below is a generic example and is commented out because the specific
// implementation depends on your application's architecture.
// window.addEventListener('beforeunload', cleanup);