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:
- The store you want to use (
counterStore). - 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 theCountercomponent listen only to changes in thecountproperty. - 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.