Skip to main content

API: store.get()

The store.get() method provides a direct way to access the current state of a SoulState store. It is used for non-reactive reads, typically outside of React components or within actions where you need a snapshot of the current state without triggering re-renders.

Summary

store.get() returns the current state object held by the store. It is a synchronous, non-reactive operation.

Function Signature

interface Store<T> {
get: () => T;
// ... other methods
}

Parameters

None.

Return Value

  • T: The current state object of the store.

Usage Examples

Basic Usage: Reading State Outside React

You can call get() directly on your store instance to get its current value.

import { counterStore } from '../stores/counterStore';

// Get the entire state
const currentState = counterStore.get();
console.log('Current state:', currentState);

// Get specific property
const currentCount = counterStore.get().count;
console.log('Current count:', currentCount);

Advanced Usage: Within Actions

get() is often used within actions to derive new state based on the current state.

import { createStore } from 'soulstate';

// Create store
export const todoStore = createStore({
todos: []
});

// Define actions that use store.get()
export const todoActions = {
addTodo: (text: string) => {
todoStore.set(state => ({
todos: [...state.todos, { id: Date.now(), text, completed: false }]
}));
},

toggleAll: () => {
// Use get() to read current state non-reactively
const currentTodos = todoStore.get().todos;
const allCompleted = currentTodos.every(todo => todo.completed);

todoStore.set(state => ({
todos: state.todos.map(todo => ({
...todo,
completed: !allCompleted
}))
}));
},

getCompletedCount: () => {
// Utility function using get()
return todoStore.get().todos.filter(todo => todo.completed).length;
}
};

Usage in Event Handlers

import { counterStore, counterActions } from '../stores/counterStore';

function SomeComponent() {
const handleComplexAction = () => {
// Read current state in event handler
const currentCount = counterStore.get().count;

if (currentCount > 10) {
console.log('Count is already high:', currentCount);
return;
}

// Perform multiple updates
counterActions.increment();
counterActions.increment();

// Verify the final state
console.log('Final count:', counterStore.get().count);
};

return (
<button onClick={handleComplexAction}>
Complex Action
</button>
);
}

Anti-patterns

1. Using get() for Reactive UI Updates

Never use store.get() directly in a React component's render logic if you expect the component to re-render when the state changes. get() is non-reactive. For reactive updates, always use the useStore hook.

// ❌ Anti-pattern: This component will NOT update when count changes
function BadCounter() {
const count = counterStore.get().count; // Stale value after updates
return <div>Count: {count}</div>;
}

// ✅ Correct: Use useStore hook for reactive updates
import { useStore } from 'soulstate/react';
function GoodCounter() {
const count = useStore(counterStore, state => state.count);
return <div>Count: {count}</div>;
}

2. Using get() Instead of Functional Updates

Avoid using get() when a functional update would be more appropriate.

// ❌ Less optimal: Multiple store interactions
const increment = () => {
const current = counterStore.get().count;
counterStore.set({ count: current + 1 });
};

// ✅ Better: Single atomic update with functional set
const increment = () => {
counterStore.set(state => ({ count: state.count + 1 }));
};

Performance Notes

store.get() is an extremely fast, O(1) operation. It simply returns a reference to the current state object. It involves:

  • ✅ No subscriptions
  • ✅ No change detection
  • ✅ No equality checks
  • ✅ No re-renders

Common Use Cases

Logging and Debugging

// Useful for debugging state changes
const logState = () => {
console.log('Current store state:', counterStore.get());
};

// Or in development
if (process.env.NODE_ENV === 'development') {
window.getStoreState = () => counterStore.get();
}

Conditional Logic in Actions

export const authActions = {
login: (credentials: any) => {
// Check current state before proceeding
if (authStore.get().isLoading) {
console.log('Already loading, skipping...');
return;
}

authStore.set({ isLoading: true });
// ... login logic
}
};

Integration with Non-React Code

// Using SoulState stores in vanilla JS
document.getElementById('save-btn').addEventListener('click', () => {
const currentData = formStore.get();
saveToLocalStorage('form-data', currentData);
});

// In Node.js scripts
const currentConfig = configStore.get();
generateReport(currentConfig);

Best Practices

✅ Do:

  • Use get() for one-off reads in event handlers
  • Use get() in actions for conditional logic
  • Use get() for debugging and logging
  • Use get() when integrating with non-React code

❌ Don't:

  • Use get() for reactive UI updates
  • Call get() excessively in performance-critical loops
  • Use get() when functional set() would suffice
  • Forget that get() returns stale data in async contexts
⚠️

Async Context Warning

In asynchronous code, the state returned by get() might be stale if other updates occur before your async operation completes. For async scenarios, consider storing the needed values in local variables before the async call.

Key Takeaway

store.get() is your tool for non-reactive state access. Use it for reading current state in actions, event handlers, and non-React code. For any data that should update your UI reactively, always use useStore.