Sizing and Scoping a Store
First, let's look at this example:
import { Store } from '@geajs/core'
class HugeApplicationStore extends Store {
// Used by Foo Component
bar = 0
baz = 'Hello World!'
// Used by Qux Component
quux: 'me' | 'us' = 'me'
// Used by Corge Component
grault: number[] = []
}
This approach to state management is poor coding practice. Bundling every piece of unrelated state — used by entirely different, unrelated parts of the application — into a single massive Store breaks loose coupling: any change to Foo's state now lives in the same class as Qux's and Corge's, so anyone touching HugeApplicationStore has to understand the whole thing, and testing one concern in isolation means mocking or stubbing out state that has nothing to do with it. Development velocity and maintainability suffer as the store grows.
However, splitting Stores too finely is not advisable either — it becomes difficult to know where a given piece of state lives, and keeping fragmented stores in sync with each other introduces its own coordination overhead. Both extremes are patterns to avoid. So, what is the ideal level of granularity?
| Properties of States | Recommended Scope | Delivery Method |
|---|---|---|
| Internal state of a single component (e.g., open/closed flag) | Local Variables / Properties of this | Not needed |
| Shared only within a single component tree | Local Store Generated at the Root of the Tree | Via props or via Context |
| Shared Across the Entire App and Multiple Separate Trees | Global Store (Module-Level Singleton) | Import and reference directly |
When in doubt, start local. Promote state to a wider scope only once more than one place genuinely needs it — pulling state up later is straightforward, but untangling an over-shared store later is not.