State Management
This page’s content is being updated
This guide covers the internal state management system of the Privacy Boost TypeScript SDK.
Overview
The SDK uses Zustand for state management. This provides reactive state updates that can be subscribed to from any part of your application.
Available Stores
| Store | Purpose |
|---|
useSDKStore | SDK initialization state |
useWalletStore | Wallet connection and authentication |
useBalanceStore | Token balance cache |
useTransactionStore | Transaction history and pending txs |
useTokenStore | Token metadata cache |
useContactStore | Contacts storage |
SDK Store
Tracks SDK initialization:
import { useSDKStore } from '@testinprod-io/privacy-boost';
const { initialized, loading, error } = useSDKStore();
if (loading) {
console.log('SDK is initializing...');
}
if (error) {
console.log('Initialization failed:', error);
}
if (initialized) {
console.log('SDK is ready');
}
Wallet Store
Tracks wallet connection and authentication:
import { useWalletStore } from '@testinprod-io/privacy-boost';
const {
isConnected,
isAuthenticated,
address,
chainId,
privacyAddress,
mpk,
} = useWalletStore();
Subscribing to Changes
// Subscribe to specific state changes
const unsubscribe = useWalletStore.subscribe(
(state) => state.isConnected,
(isConnected) => {
console.log('Connection changed:', isConnected);
}
);
// Cleanup
unsubscribe();
Balance Store
Caches token balances:
import { useBalanceStore } from '@testinprod-io/privacy-boost';
const {
balances, // Map<tokenAddress, TokenBalance>
loading,
lastUpdated,
} = useBalanceStore();
// Get balance for specific token
const tokenBalance = balances.get('0x...token-address');
if (tokenBalance) {
console.log('Shielded:', tokenBalance.shielded);
console.log('Wallet:', tokenBalance.wallet);
}
Balance Actions
import { useBalanceStore } from '@testinprod-io/privacy-boost';
const { updateBalance, clearBalances } = useBalanceStore.getState();
// Manually update a balance
updateBalance('0x...token', {
shielded: 1000000000000000000n,
wallet: 500000000000000000n,
});
// Clear all cached balances
clearBalances();
Transaction Store
Tracks transaction history and pending transactions:
import { useTransactionStore } from '@testinprod-io/privacy-boost';
const {
transactions, // Transaction[]
pending, // Transaction[]
loading,
} = useTransactionStore();
// Get recent transactions
const recent = transactions.slice(0, 10);
// Get pending transactions
for (const tx of pending) {
console.log(`Pending: ${tx.txHash} - ${tx.type}`);
}
Transaction Actions
const { addTransaction, updateTransaction, clearTransactions } =
useTransactionStore.getState();
// Add a new transaction
addTransaction({
txHash: '0x...',
type: 'deposit',
status: 'pending',
tokenAddress: '0x...',
amount: 1000000000000000000n,
createdAt: Date.now(),
updatedAt: Date.now(),
});
// Update transaction status
updateTransaction('0x...txHash', {
status: 'completed',
});
Token Store
Caches token metadata:
import { useTokenStore } from '@testinprod-io/privacy-boost';
const { tokens, getToken } = useTokenStore();
// Get cached token
const token = getToken('0x...token-address');
if (token) {
console.log(`${token.symbol} (${token.decimals} decimals)`);
}
Stores contacts locally:
import { useContactStore } from '@testinprod-io/privacy-boost';
const { contacts, addContact, removeContact, updateContact } = useContactStore();
// List all contacts
for (const contact of contacts) {
console.log(`${contact.name}: ${contact.privacyAddress}`);
}
React Integration
Using Stores in Components
import { useWalletStore, useBalanceStore } from '@testinprod-io/privacy-boost';
function WalletInfo() {
// Reactive - re-renders on state change
const { isAuthenticated, privacyAddress } = useWalletStore();
const { balances } = useBalanceStore();
if (!isAuthenticated) {
return <div>Not authenticated</div>;
}
return (
<div>
<p>Address: {privacyAddress}</p>
<p>Tokens: {balances.size}</p>
</div>
);
}
Selecting Specific State
function Balance({ tokenAddress }: { tokenAddress: string }) {
// Only re-renders when this specific balance changes
const balance = useBalanceStore(
(state) => state.balances.get(tokenAddress)
);
if (!balance) return null;
return <span>{balance.shielded.toString()}</span>;
}
Using Outside React
// Get current state
const state = useWalletStore.getState();
console.log('Current address:', state.address);
// Subscribe to changes
const unsubscribe = useWalletStore.subscribe((state) => {
console.log('Wallet state changed:', state);
});
Custom Store Composition
Create derived state from multiple stores:
import { useMemo } from 'react';
import { useWalletStore, useBalanceStore } from '@testinprod-io/privacy-boost';
function useTotalBalance() {
const { isAuthenticated } = useWalletStore();
const { balances } = useBalanceStore();
return useMemo(() => {
if (!isAuthenticated) return 0n;
let total = 0n;
for (const balance of balances.values()) {
total += balance.shielded;
}
return total;
}, [isAuthenticated, balances]);
}
Persistence
The contact store persists to localStorage by default:
// Contacts are automatically saved and restored
// You can clear persisted data:
localStorage.removeItem('privacy-boost-contacts');
Debugging
Enable Zustand devtools:
import { devtools } from 'zustand/middleware';
// Stores support devtools integration
// Open Redux DevTools to inspect state
Best Practices
1. Select Only What You Need
// BAD - Re-renders on any state change
const state = useWalletStore();
// GOOD - Only re-renders when address changes
const address = useWalletStore((state) => state.address);
2. Use Shallow Comparison for Objects
import { shallow } from 'zustand/shallow';
// Re-renders only when these specific values change
const { address, chainId } = useWalletStore(
(state) => ({ address: state.address, chainId: state.chainId }),
shallow
);
3. Memoize Derived State
const sortedBalances = useMemo(() => {
return Array.from(balances.values()).sort(
(a, b) => Number(b.shielded - a.shielded)
);
}, [balances]);
4. Clean Up Subscriptions
useEffect(() => {
const unsubscribe = useWalletStore.subscribe((state) => {
// Handle state changes
});
return () => unsubscribe();
}, []);
Next Steps