Systems-Grade Performance Tuning
SoulState is fast by default, but for large-scale applications with 100,000+ subscribers and complex reactive graphs, specific patterns can help you maintain peak systems-grade performance.
1. Maximize Selector Granularity
The most effective way to optimize SoulState is to minimize $M$ (the number of affected nodes).
// ❌ Suboptimal: Re-renders when ANY property of 'user' changes
const user = useStore(store, s => s.user);
// ✅ Optimal: Only re-renders when 'name' changes
const name = useStore(store, s => s.user.name);
By subscribing to the smallest possible leaf node in your state tree, you ensure that the Invalidation Graph can skip your component for unrelated updates.
2. Offload Computations to computed
If your selector performs expensive operations (filtering, sorting, mapping), move them into a computed node.
// ❌ Expensive: Runs on every render if dependencies change
function List() {
const items = useStore(store, s => s.items.filter(i => i.active));
}
// ✅ Efficient: Cached and only re-runs when 'items' actually changes
const activeItemsNode = store.computed(s => s.items.filter(i => i.active));
function List() {
const items = useStore(store, () => activeItemsNode.value);
}
3. Leverage Transactions for Batching
If you need to update multiple keys that are logically related, use a Transaction. This reduces the number of propagation cycles from $N$ to 1.
// Triggers ONE flush instead of TWO
store.beginTransaction();
store.setState({ loading: true });
store.setState({ data: null });
store.commitTransaction();
4. Use shallow for Object Literals
If your selector must return a new object (e.g., when picking multiple properties), always use the shallow equality function to prevent redundant re-renders.
import { shallow } from 'soulstate/utils';
const { name, email } = useStore(
store,
s => ({ name: s.user.name, email: s.user.email }),
shallow
);
5. Profile with Instrumentation
Enable built-in instrumentation to identify "hot" selectors that are dragging down your flush performance.
store.enableInstrumentation({
onSelectorRun: (name, duration) => {
if (duration > 1) {
console.warn(`Slow Selector: ${String(name)} took ${duration}ms`);
}
}
});
Memory vs. Speed Tradeoffs
In extreme scale scenarios, you can tune SoulState's memory footprint:
- Computed Pruning: Call
node.destroy()on computeds that are no longer needed to remove them from the Invalidation Graph. - Granular vs. Global: If you have 10,000 components that always update together, a single global subscription might be more memory-efficient than 10,000 granular ones, though this is rare in modern UI design.
Systems-Grade Efficiency
Performance tuning in SoulState is about aligning your application's data usage with the runtime's Invalidation Graph. When you use granular selectors and computed nodes, SoulState's engine can achieve throughput that global-broadcast libraries simply cannot match.