Cached Getters
Cached getters provide a way to declare state derivations in a getter format. The value is only calculated when the getter function is called, and once calculated, it's cached for O(1) reads until dependencies change.
Basic Usage
1. Define State with Function Properties
2. Create Store with Derivations
3. Use in Components
4. Use in Reducers
Features
- Lazy Evaluation: Values are only calculated when the getter is called
- Automatic Caching: Results are cached and reused until dependencies change
- Dependency Tracking: Automatically detects when dependencies change and invalidates cache
- Type Safety: Full TypeScript support with proper type inference
- Use anywhere: You can read in hook selectors and reducers
Important to know:
- Functions inside the state object will be turned into cached getters
- You can try to set the property with another value, but it will be overridden once the value is read
In depth
Selectors
Selectors extract values from the state that the derivation depends on. The order of selectors determines the order of arguments passed to the evaluator.
Evaluator
The evaluator function receives the values from selectors as arguments and returns the computed value.
Caching Strategy
- Cache Invalidation: Automatically invalidates when any dependency changes
Performance Benefits
- Lazy Evaluation: Values are only computed when needed
- Automatic Caching: Subsequent calls return cached results
- Dependency Tracking: Only recalculates when dependencies actually change
- Memory Efficient: No unnecessary object creation
Best Practices
- Keep Selectors Simple: Selectors should be pure functions that extract values
- Use Multiple Selectors: Break down complex dependencies into multiple selectors
- Avoid Side Effects: Evaluators should be pure functions
Examples
Simple Counter
Complex Todo App
Migration Guide
From Manual Selectors
Before:
- ❌ - Bad practice: avoid calculations in selectors, they run multiple times per render.
- ❌ - Each selector runs a calculation.
After:
- ✅ - Using cached getters, the calculation runs only once and is re-used across many selectors and many renders.
From useMemo
Before:
- ❌ - Derived at component level, can't be used in reducers
- ❌ - Requires multiple hooks instead of one unified solution
- ❌ - If other components need
completedCount
, the calculation runs once per component that needs the value
After:
- ✅ - Using cached getters, the calculation runs only once and is re-used across many selectors and many renders.
Limitations
- Synchronous Only: Evaluators must be synchronous functions
- For async derivation, read async derivation value
Troubleshooting
Cache Not Updating
If cached getters are not updating:
- Check that selectors are returning the correct dependencies
- Verify that the state is actually changing
- Ensure evaluator is pure and deterministic
Performance Issues
If performance is poor:
- Break down complex selectors into smaller ones
- Use more specific selectors to minimize cache invalidation