Skip to main content

System Architecture

This document provides a comprehensive overview of SoulState's internal architecture, explaining how the library achieves optimal performance through intelligent design choices.

Core Components

SoulState's architecture consists of four main systems working in harmony:

  1. The Store: Manages state with get, set, and subscribe methods
  2. The Subscription Manager: Uses doubly linked lists for O(1) operations
  3. The Update Pipeline: Batches updates with microtasks and structural sharing
  4. React Integration: Leverages useSyncExternalStore for optimal rendering

System Flow Diagram

graph TD
subgraph React Component
A[User Action] --> B[store.set];
end

subgraph SoulState Core
B --> C[Change Detection];
C --> D{Values Changed?};
D -->|No| E[Early Return];
D -->|Yes| F[Structural Sharing];
F --> G[Schedule Microtask];
G --> H[queueMicrotask];
end

subgraph Notification Phase
H --> I[Notify Subscribers];
I --> J[Linked List Traversal];
J --> K[Run Selectors];
K --> L[Equality Check];
L --> M[Trigger Re-render];
end

subgraph React Integration
M --> N[useSyncExternalStore];
N --> O[Component Re-render];
end

1. The Store (createStore)

The foundation of SoulState - a minimal, performant state container.

import { createSubscriptionManager } from './subscriptions';

export interface Store<T> {
get: () => T;
set: (updater: StateUpdater<T>) => void;
subscribe: <S>(
selector: (state: T) => S,
listener: (selectedState: S, prevSelectedState: S) => void,
options?: { equalityFn?: (a: S, b: S) => boolean }
) => () => void;
}

export function createStore<T extends object>(initialState: T): Store<T> {
let state: T = initialState;
const subscriptionManager = createSubscriptionManager<T>();
let isNotificationScheduled = false;
let lastKnownState = state;

const notifySubscribers = () => {
subscriptionManager.notify(state, lastKnownState);
lastKnownState = state;
isNotificationScheduled = false;
};

const scheduleNotification = () => {
if (!isNotificationScheduled) {
isNotificationScheduled = true;
queueMicrotask(notifySubscribers);
}
};

const get = (): T => state;

const set = (updater: StateUpdater<T>) => {
const partialState = typeof updater === 'function'
? (updater as (state: T) => Partial<T> | T)(state)
: updater;

if (Object.is(partialState, state) || partialState === undefined) {
return;
}

// Minimal Structural Sharing - check if values actually changed
let hasChanged = false;
const updatedKeys = Object.keys(partialState);
for (let i = 0; i < updatedKeys.length; i++) {
const key = updatedKeys[i] as keyof T;
if (!Object.is(state[key], (partialState as T)[key])) {
hasChanged = true;
break;
}
}

if (!hasChanged) {
return; // No actual change - avoid object creation
}

// Only create new object if something truly changed
const nextState = { ...state, ...(partialState as Partial<T>) };
state = nextState;
scheduleNotification();
};

const subscribe = <S>(
selector: (state: T) => S,
listener: (selectedState: S, prevSelectedState: S) => void,
options?: { equalityFn?: (a: S, b: S) => boolean }
) => {
return subscriptionManager.subscribe(selector, listener, options?.equalityFn, state);
};

return { get, set, subscribe };
}
ℹ️

Design Philosophy

The store is a simple closure that encapsulates state with minimal overhead. The key innovation is the change detection that prevents unnecessary object creation and the microtask batching that ensures optimal update scheduling.

2. The Subscription Manager

A doubly linked list implementation for optimal subscription management.

import { objectIs } from '../utils/equality';

// A node in the doubly linked list of subscribers
interface SubscriptionNode<T, S> {
selector: (state: T) => S;
listener: (selectedState: S, prevSelectedState: S) => void;
equalityFn: (a: S, b: S) => boolean;
lastState: S;
prev: SubscriptionNode<T, any> | null;
next: SubscriptionNode<T, any> | null;
}

export function createSubscriptionManager<T>(): SubscriptionManager<T> {
// Head and tail pointers for the doubly linked list
let head: SubscriptionNode<T, any> | null = null;
let tail: SubscriptionNode<T, any> | null = null;

const subscribe = <S>(
selector: (state: T) => S,
listener: (selectedState: S, prevSelectedState: S) => void,
equalityFn: (a: S, b: S) => boolean = objectIs,
initialState: T
) => {
const newNode: SubscriptionNode<T, S> = {
selector,
listener,
equalityFn,
lastState: selector(initialState),
prev: tail,
next: null,
};

// O(1) insertion at tail
if (tail) {
tail.next = newNode;
} else {
head = newNode;
}
tail = newNode;

// Return O(1) unsubscribe function
return () => {
const { prev, next } = newNode;
if (prev) {
prev.next = next;
} else {
head = next;
}
if (next) {
next.prev = prev;
} else {
tail = prev;
}
};
};

const notify = (newState: T, prevState: T) => {
if (Object.is(newState, prevState)) return;

// Iterate through linked list - no iterator overhead
let current = head;
while (current) {
const sub = current;
const newSelectedState = sub.selector(newState);
const lastState = sub.lastState;

if (!sub.equalityFn(newSelectedState, lastState)) {
sub.lastState = newSelectedState;
sub.listener(newSelectedState, lastState);
}

current = current.next;
}
};

return { subscribe, notify };
}
ℹ️

Why Doubly Linked List?

While Map and Set offer O(1) operations, a doubly linked list provides direct pointer manipulation without iterator creation overhead. This results in faster iteration during notifications and instant O(1) subscription removal.

3. Update Pipeline & Performance Optimizations

SoulState employs multiple optimization strategies for maximum performance.

Microtask Batching

let isNotificationScheduled = false;

const scheduleNotification = () => {
if (!isNotificationScheduled) {
isNotificationScheduled = true;
queueMicrotask(notifySubscribers); // Batched!
}
};

// Multiple updates → single re-render
store.set({ count: 1 }); // 🚫 No immediate notification
store.set({ count: 2 }); // 🚫 No immediate notification
store.set({ count: 3 }); // 🚫 No immediate notification
// ✅ Single notification with final state

Structural Sharing & Change Detection

// Instead of blind object spreading, check for actual changes
let hasChanged = false;
const updatedKeys = Object.keys(partialState);
for (let i = 0; i < updatedKeys.length; i++) {
const key = updatedKeys[i] as keyof T;
if (!Object.is(state[key], (partialState as T)[key])) {
hasChanged = true;
break;
}
}

if (!hasChanged) {
return; // Skip object creation and notifications
}

// Only create new object when necessary
const nextState = { ...state, ...(partialState as Partial<T>) };

Selective Notification

// Only notify subscribers whose selected data changed
if (!sub.equalityFn(newSelectedState, lastState)) {
sub.lastState = newSelectedState;
sub.listener(newSelectedState, lastState); // Trigger re-render
}

4. React Integration

Seamless integration with React 18+ using modern concurrent features.

import * as React from 'react';
import { Store } from '../core/store';
import { objectIs } from '../utils/equality';
import { shallow } from '../utils/shallow';

// Use React 18's useSyncExternalStore when available
const useSyncExternalStore =
React.useSyncExternalStore ||
((subscribe, getSnapshot) => {
const value = getSnapshot();
const [state, setState] = React.useState(value);
React.useLayoutEffect(() => {
const unsubscribe = subscribe(() => {
const nextValue = getSnapshot();
if (!Object.is(value, nextValue)) {
setState(nextValue);
}
});
return unsubscribe;
}, [subscribe, getSnapshot]);
return state;
});

export function useStore<T, S>(
store: Store<T>,
selector: (state: T) => S,
equalityFn: (a: S, b: S) => boolean = objectIs
): S {
const getSnapshot = React.useCallback(() => selector(store.get()), [store, selector]);

const subscribe = React.useCallback(
(onStoreChange: () => void) => {
const unsubscribe = store.subscribe(selector, onStoreChange, { equalityFn });
return unsubscribe;
},
[store, selector, equalityFn]
);

const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
return value;
}

// Convenience hook for shallow object comparisons
export const useShallow = <T, S>(store: Store<T>, selector: (state: T) => S) =>
useStore(store, selector, shallow);

5. Utility Functions

SoulState provides optimized utilities for common patterns.

Equality Functions

// Default referential equality
export const objectIs = (a: any, b: any): boolean => Object.is(a, b);

// Shallow object comparison
export const shallow = <T, U>(a: T, b: U): boolean => {
if (Object.is(a, b)) return true;
if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) {
return false;
}

const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;

for (let i = 0; i < keysA.length; i++) {
const key = keysA[i];
if (!Object.prototype.hasOwnProperty.call(b, key) ||
!Object.is((a as any)[key], (b as any)[key])) {
return false;
}
}
return true;
};

Performance Characteristics

Time Complexity

  • Subscription Management: O(1) for add/remove
  • State Updates: O(k) where k = changed properties
  • Notifications: O(n) where n = active subscriptions
  • Selector Execution: O(1) per subscription

Space Complexity

  • Store: O(1) additional memory
  • Subscriptions: O(n) where n = active subscriptions

Best Practices

✅ Do:

  • Use precise selectors to subscribe to minimal data
  • Leverage shallow equality for object selections
  • Trust automatic batching for multiple updates
  • Keep selectors pure and dependency-free

❌ Don't:

  • Select entire state objects unnecessarily
  • Create new objects in selectors without proper equality
  • Mutate state directly - always use set()
  • Worry about micro-optimizations - SoulState handles them
⚠️

Anti-Pattern: Over-Subscription

Avoid subscribing to more state than necessary. Each subscription adds overhead during notifications. Use surgical selectors to subscribe only to the data your component actually needs.

Key Takeaways

  1. Minimal Overhead: O(1) subscription management with automatic batching
  2. Predictable Updates: Microtask-based pipeline ensures consistency
  3. React Optimized: Built on useSyncExternalStore for concurrent features
  4. Developer Friendly: Simple API with sophisticated optimizations

Architecture Summary

SoulState combines a minimal store interface with a highly optimized subscription system and batched update pipeline. This architecture delivers exceptional performance while maintaining a simple, predictable developer experience.