Skip to main content

Getting Started

Welcome to SoulState! This guide will walk you through creating a store and connecting it to a React component. By the end, you'll see how SoulState enables surgical, high-performance state updates with minimal boilerplate.

1. Installation

First, install SoulState using your preferred package manager.

npm install soulstate

SoulState has no external dependencies, keeping your bundle size lean.

2. Creating a Store

A "store" is an object that holds your state and provides methods to read and update it. You create one with the createStore function.

Let's define a simple counter store in a file named store.ts.

import { createStore } from 'soulstate';

// Create the store with initial state
export const counterStore = createStore({
count: 0
});

// Define actions as separate functions
export const counterActions = {
increment: () => counterStore.set((state) => ({ count: state.count + 1 })),
decrement: () => counterStore.set((state) => ({ count: state.count - 1 })),
reset: () => counterStore.set({ count: 0 })
};
ℹ️

What's happening here?

createStore takes the initial state as its argument. We then define actions as separate functions that use the store's set method to update the state.

3. Connecting to React Components

To use the store in a React component, import the useStore hook from soulstate/react and the store you just created.

The useStore hook requires two arguments:

  1. The store you want to use (counterStore).
  2. A selector function that picks a piece of state.
import { useStore } from 'soulstate/react';
import { counterStore, counterActions } from './store';

// A selector to get the count value
const selectCount = (state) => state.count;

export function Counter() {
// This component subscribes ONLY to the 'count' value
const count = useStore(counterStore, selectCount);

return (
<div>
<h1>Count: {count}</h1>
<button onClick={counterActions.increment}>+1</button>
<button onClick={counterActions.decrement}>-1</button>
<button onClick={counterActions.reset}>Reset</button>
</div>
);
}

The Power of Selectors

The key to SoulState's performance is the selector pattern:

  • The useStore(counterStore, selectCount) call makes the Counter component listen only to changes in the count property.
  • If other properties were added to the store, this component would not re-render when they change.
  • Actions are called directly from the imported counterActions, maintaining clean separation of concerns.

This fine-grained subscription model ensures your component only re-renders when the exact data it needs has changed, eliminating wasted renders and keeping your UI fast and responsive.

⚠️

Import Path Note

Make sure to import useStore from 'soulstate/react' for React components, not from the main package.

🔥

Anti-Pattern: Selecting the Whole State

Avoid selecting the entire state object in a single hook: const state = useStore(counterStore, state => state); This will cause the component to re-render on every state change, defeating the purpose of selector-based subscriptions.

4. Advanced Pattern: Multiple Selectors

For more complex components, you can use multiple selectors to subscribe to different pieces of state:

import { useStore } from 'soulstate/react';
import { counterStore, counterActions } from './store';

export function Counter() {
// Subscribe to multiple pieces of state independently
const count = useStore(counterStore, (state) => state.count);
const isPositive = useStore(counterStore, (state) => state.count > 0);
const isEven = useStore(counterStore, (state) => state.count % 2 === 0);

return (
<div>
<h1>Count: {count}</h1>
<p>Positive: {isPositive ? '✅' : '❌'}</p>
<p>Even: {isEven ? '✅' : '❌'}</p>
<button onClick={counterActions.increment}>+1</button>
<button onClick={counterActions.decrement}>-1</button>
</div>
);
}
💡

Pro Tip

Each useStore call creates an independent subscription. Components only re-render when their specific selected values change, giving you surgical control over performance.