Troubleshooting Guide
Common issues and solutions when using SoulState.
Installation Issues
Module not found
Error:
Module not found: Can't resolve 'soulstate'
Solution:
npm install soulstate
# or
yarn add soulstate
# or
pnpm add soulstate
TypeScript errors
Error:
Cannot find module 'soulstate' or its corresponding type declarations.
Solution: Ensure you have the latest version and TypeScript is configured correctly:
npm install soulstate@latest
npm install -D typescript@latest
Store Creation Issues
Store not reactive
Symptom: State changes don't trigger re-renders.
Solution: Ensure you're using the store hook correctly:
// Wrong - accessing state directly
const count = store.getState().count;
// Correct - using useStore hook
const count = useStore(store, (state) => state.count);
Multiple stores conflict
Symptom: Updates to one store affect another.
Solution: Each store is independent. Ensure you're using the correct store instance:
const storeA = createStore({ a: 1 });
const storeB = createStore({ b: 2 });
// Each store is separate
useStore(storeA, (state) => state.a);
useStore(storeB, (state) => state.b);
Subscription Issues
Subscription not firing
Symptom: Listener doesn't execute when state changes.
Solution:
-
Check the selector function:
// Wrong - selector returns same referencestore.subscribe((state) => state, // Always returns same object(state) => console.log(state));// Correct - selector returns specific valuestore.subscribe((state) => state.count,(count) => console.log(count)); -
Verify the subscription is active:
const unsubscribe = store.subscribe((state) => state.count,(count) => console.log(count));// Subscription is active until unsubscribedunsubscribe(); // Now it's inactive
Memory leak from subscriptions
Symptom: Memory usage grows over time.
Solution: Always unsubscribe when component unmounts:
useEffect(() => {
const unsubscribe = store.subscribe(
(state) => state.count,
(count) => console.log(count)
);
return () => unsubscribe(); // Cleanup on unmount
}, []);
Computed Value Issues
Computed not updating
Symptom: Computed value doesn't reflect changes.
Solution: Ensure computed is accessing the correct state:
// Wrong - computed not accessing state
const double = store.computed(() => 2); // Static value
// Correct - computed accessing state
const double = store.computed((state) => state.count * 2);
Computed re-computing too often
Symptom: Computed function runs excessively.
Solution: SoulState caches computed values. If it's re-computing, check:
- Dependencies are changing
- Selector is deterministic
- No external state is being accessed
Performance Issues
Slow updates with many subscribers
Symptom: Updates are slow with 1000+ subscribers.
Solution: Use surgical selectors:
// Wrong - triggers all subscribers
store.subscribe(
(state) => state, // Returns entire state
(state) => { /* ... */ }
);
// Correct - triggers only relevant subscribers
store.subscribe(
(state) => state.specificKey, // Returns only what you need
(value) => { /* ... */ }
);
Unnecessary re-renders
Symptom: Components re-render when they shouldn't.
Solution: Use shallow equality for object selections:
import { shallow } from 'soulstate/utils';
useStore(
store,
(state) => ({ a: state.a, b: state.b }),
shallow // Prevents re-render if a and b haven't changed
);
React Integration Issues
useStore not working
Symptom: useStore hook throws error.
Solution: Ensure you're using the correct import:
// Wrong
import { useStore } from 'soulstate';
// Correct
import { useStore } from 'soulstate/react';
Provider not found
Symptom: Error about missing context provider.
Solution: Wrap your app with the Provider:
import { Provider } from 'soulstate/react';
function App() {
return (
<Provider store={store}>
<MyComponent />
</Provider>
);
}
Transaction Issues
Transaction not batching
Symptom: Updates happen immediately instead of batching.
Solution: Use the transaction API:
store.beginTransaction();
store.setState({ count: 1 });
store.setState({ name: 'updated' });
// Both updates happen atomically
store.commitTransaction();
Transaction rollback not working
Symptom: State changes persist after rollback.
Solution: Ensure you're in a transaction:
store.beginTransaction();
try {
store.setState({ count: 1 });
store.setState({ count: 2 });
store.rollbackTransaction(); // Reverts to state before transaction
} catch (error) {
store.rollbackTransaction();
}
Debugging Tips
Enable instrumentation
store.enableInstrumentation({
onFlush: (duration, keys) => {
console.log('Flush duration:', duration);
},
onSelectorRun: (name, duration) => {
console.log('Selector:', String(name), 'took', duration, 'ms');
}
});
// Access metrics
const metrics = store.getMetrics();
if (metrics) {
console.log('Average Flush Time:', metrics.averageFlushDuration);
console.log('Selector Runs:', metrics.selectorRunCount);
}
Check store state
// Current state
console.log(store.getState());
// Previous state (during update)
store.subscribe(
(state) => state.count,
(count, prevCount) => {
console.log('Updated from', prevCount, 'to', count);
}
);