Skip to main content

API: Utilities

SoulState provides utility functions for selector composition, scheduling, batching, and equality checks.

Import Paths

UtilityImport
batch, objectIs, createSlice, combineSlicesimport { ... } from 'soulstate'
shallow, batch, objectIs, createSlice, combineSlicesimport { ... } from 'soulstate/utils'
createSelector, selector, derivedimport { ... } from 'soulstate'
scheduleTask, flushSyncimport { ... } from 'soulstate'
⚠️

Import Path

shallow is only available from 'soulstate/utils'. It is not exported from the main 'soulstate' entry.


shallow

Performs a shallow comparison of two objects, checking if their top-level properties are equal using Object.is.

Signature

function shallow<T, U>(a: T, b: U): boolean;

Parameters

  • a: T — The first value to compare.
  • b: U — The second value to compare.

Return Value

booleantrue if all top-level properties are equal, false otherwise.

When to Use

Use shallow as an equalityFn when your selector returns a new object literal on each render but with the same values:

import { useStore } from 'soulstate/react';
import { shallow } from 'soulstate/utils';

function UserProfile() {
const { name, email } = useStore(
userStore,
(state) => ({ name: state.name, email: email: state.email }),
shallow
);
return <div>{name}{email}</div>;
}

When NOT to Use

  • For primitive values — use the default Object.is instead.
  • For deeply nested comparisons — shallow only checks top-level properties.

objectIs

The default equality function used by SoulState. Equivalent to Object.is.

Signature

const objectIs: (a: any, b: any) => boolean;

Behavior

import { objectIs } from 'soulstate';

objectIs(1, 1); // true
objectIs(NaN, NaN); // true
objectIs(0, -0); // false
objectIs({}, {}); // false

batch

Groups multiple operations into a single callback. SoulState automatically batches all setState calls via microtasks, so this utility is primarily for semantic grouping.

Signature

function batch(callback: () => void): void;

Usage

import { batch } from 'soulstate';

batch(() => {
store.setState({ count: 1 });
store.setState({ user: 'John' });
});

createSelector

Creates a memoized selector that caches its result until the input slice changes.

Signature

function createSelector<T, S, R>(
selector: (state: T) => S,
combiner: (val: S) => R,
equalityFn?: (a: S, b: S) => boolean
): (state: T) => R;

Parameters

  • selector — Extracts a slice from the state.
  • combiner — Transforms the slice into a derived value.
  • equalityFn — Optional comparison function (defaults to Object.is).

Return Value

A new selector function that memoizes its result.

Usage

import { createSelector } from 'soulstate';

const selectDoubled = createSelector(
(s: { count: number }) => s.count,
(count) => count * 2
);

// First call: computes
selectDoubled(store.getState()); // 2

// Second call with same input: returns cached result
selectDoubled(store.getState()); // 2 (no recomputation)

selector

Identity function for type inference. Returns the function unchanged.

Signature

function selector<T, S>(fn: (state: T) => S): (state: T) => S;

Usage

import { selector } from 'soulstate';

const selectCount = selector((s: { count: number }) => s.count);
selectCount({ count: 42 }); // 42

derived

Composable selector utility. Combines multiple selectors or computed values into a single derived selector.

Signature

function derived<T, S extends any[], R>(
...args: [
...{ [K in keyof S]: ((state: T) => S[K]) | { value: S[K] } },
(...vals: S) => R
]
): (state: T) => R;

Parameters

  • ...selectors — An array of selector functions or Computed objects, followed by a combiner function as the last argument.

Return Value

A new selector function that computes the derived value.

Usage

import { derived } from 'soulstate';

const selectFullName = derived(
(s: { first: string; last: string }) => s.first,
(s: { first: string; last: string }) => s.last,
(first, last) => `${first} ${last}`
);

selectFullName({ first: 'Jane', last: 'Doe' }); // "Jane Doe"

Composing with Computed

import { createStore, derived } from 'soulstate';

const store = createStore({ a: 1, b: 2 });
const aComp = store.computed(s => s.a);
const bComp = store.computed(s => s.b);

const sum = derived(aComp, bComp, (a, b) => a + b);
sum(store.getState()); // 3

scheduleTask

Schedules a task on the microtask queue. Duplicate tasks (same function reference) are deduplicated.

Signature

function scheduleTask(task: () => void): void;

Behavior

  • Tasks are executed in FIFO order during the next microtask flush.
  • If the same function reference is already queued, it is not added again.
  • Tasks scheduled during a flush are executed in a subsequent microtask.
ℹ️

Internal Use

scheduleTask is used internally by SoulState's runtime to batch state updates. You rarely need to call it directly.


flushSync

Executes a callback immediately. Unlike scheduleTask, this does NOT drain the microtask notification queue.

Signature

function flushSync<T>(callback: () => T): T;

Usage

import { flushSync } from 'soulstate';

flushSync(() => {
// Executes synchronously
console.log('runs immediately');
});
⚠️

Caution

flushSync executes the callback immediately but does not process pending microtask notifications. Subscriber notifications from prior setState calls may still be pending.


createSlice

Creates a domain-specific state slice with auto-injected actions. See Slices API for full documentation.

combineSlices

Merges multiple slice creators into a single state creator. See Slices API for full documentation.


Performance Characteristics

  • shallow: O(n) where n is the number of top-level properties.
  • objectIs: O(1) — delegates to Object.is.
  • createSelector: O(1) memoized after first call; recomputes only when input slice changes.
  • batch: No overhead — directly invokes the callback.
  • scheduleTask: O(1) enqueue; deduplicates by reference equality.
  • flushSync: O(1) — synchronous callback invocation.