Best Practices
Essential best practices for Context-Action framework development. This document provides quick references and links to comprehensive pattern guides.
<!-- Updated for sync-docs testing -->
📚 Comprehensive Pattern Documentation
This guide has been reorganized for better maintainability. For detailed implementations, see the Pattern Collection:
🎯 Core Framework Patterns
- Action Patterns - Pure action dispatching without state management
- Store Patterns - Type-safe state management (Recommended)
- RefContext Patterns - Direct DOM manipulation with zero re-renders
🏗️ Advanced Patterns
- Architecture Patterns - System architecture and design patterns
- Async Patterns - Asynchronous operation patterns and control flow
- Performance Patterns - Performance optimization techniques
- Debug Patterns - Production debugging and troubleshooting
⚠️ Critical Best Practices
🔴 Must-Read Critical Patterns
These patterns address common pitfalls that can cause serious issues in production:
1. Handler State Access - ⚠️ CRITICAL
Avoid closure traps when accessing store values in action handlers.
// ❌ WRONG: Component scope values create closure traps
function BadComponent() {
const user = useStoreValue(userStore); // Trapped in closure!
useActionHandler('updateUser', async (payload) => {
if (user.isActive) { // STALE VALUE!
await updateUserAPI(payload);
}
});
}
// ✅ CORRECT: Always get fresh state from store
function GoodComponent() {
useActionHandler('updateUser', useCallback(async (payload) => {
const currentUser = userStore.getValue(); // Real-time value!
if (currentUser.isActive) {
await updateUserAPI(payload);
}
}, [userStore]));
}📖 Read More: Handler State Access Patterns
2. Production Debugging - 🐛 ESSENTIAL
Critical issues like duplicate handlers, race conditions, and component lifecycle conflicts.
📖 Read More: Production Debugging Patterns
3. Real-time State Access - ⚡ IMPORTANT
Proper async patterns for accessing current state values.
📖 Read More: Real-time State Access
📋 Quick Reference
Essential Development Rules
✅ Always Do
- Use
useCallbackfor action handlers - Access real-time state with
store.getValue()in handlers - Choose appropriate comparison strategies for stores
- Handle errors with try-catch in action handlers
- Test both mounted/unmounted scenarios
❌ Never Do
- Use component scope values in action handlers (closure traps!)
- Register handlers without
useCallback - Use direct DOM queries (
document.getElementById) - Ignore error handling in critical operations
- Skip timeout protection for async operations
Pattern Selection Guide
// 🎯 Action Only: Pure event handling
const { useActionDispatch, useActionHandler } = createActionContext<Actions>('MyActions');
// 🏪 Store Only: Pure state management (Recommended)
const { useStore, useStoreManager } = createStoreContext('MyStores', {
data: initialData,
isLoading: false
});
// 🔧 RefContext: High-performance DOM manipulation
const { useRefHandler } = createRefContext<Refs>('MyRefs');
// 🏗️ Composition: Complex applications
function App() {
return (
<MyActionProvider>
<MyStoreProvider>
<MyRefProvider>
<AppContent />
</MyRefProvider>
</MyStoreProvider>
</MyActionProvider>
);
}📖 Detailed Documentation
Core Concepts
For naming conventions, file structure, and type definitions, see:
- Conventions Guide - Complete coding conventions
- Architecture Guide - MVVM architecture guide
- Pattern Guide - Pattern selection guide
Implementation Guides
For step-by-step implementation details, see:
- Basic Examples - Working code examples
- Pattern Collection - Comprehensive implementation guides
🚨 Common Pitfalls
⚠️ Critical Issues to Avoid
- Closure Traps: Never use component scope values in handlers
- Duplicate Handlers: Check for multiple registrations of same handler
- Race Conditions: Use processing state flags for critical actions
- Memory Leaks: Clean up refs, animations, and event listeners
- Stale State: Always use
store.getValue()for current state - Event Object Storage: Never store DOM events or React event objects in stores
- Cross-Platform Compatibility: Use proper timeout types for browser/Node.js environments
📖 Detailed Solutions: Production Debugging
🔧 Security & Performance Guidelines
Event Object Handling
Never store DOM event objects in stores as they can cause memory leaks:
// ❌ WRONG: Storing event objects causes memory leaks
function BadHandler() {
useActionHandler('handleClick', async (event) => {
// This will trigger an error and prevent storage
store.setValue({ clickEvent: event });
});
}
// ✅ CORRECT: Extract needed data from events
function GoodHandler() {
useActionHandler('handleClick', async (event) => {
// Extract only the data you need
const clickData = {
clientX: event.clientX,
clientY: event.clientY,
target: event.target?.tagName,
timestamp: Date.now()
};
store.setValue({ clickData });
});
}Memory Management
The framework automatically handles memory-heavy objects:
// EventBus automatically prevents memory leaks by:
// 1. Detecting DOM elements and React components
// 2. Storing only essential metadata instead of full objects
// 3. Cleaning up problematic references automaticallyError Handling
Use the centralized error handling system:
// Framework provides ErrorHandlers for:
// - Store operation errors
// - Event handler failures
// - Ref mount callback errors
// - Async operation failures with proper context🎯 Migration Guide
If you're migrating from other state management libraries or updating existing code:
- Identify Pattern Types: Determine which patterns (Action, Store, RefContext) you need
- Check Critical Patterns: Review handler state access and async patterns
- Update Conventions: Follow naming and file structure conventions
- Test Thoroughly: Especially focus on handler behavior and state updates
📖 Complete Migration Guide: Pattern Guide
📚 Additional Resources
Documentation Links
- API Reference - Complete API documentation
- Example Code - Working example application
- Pattern Collection - Comprehensive pattern guides
External Resources
- Context-Action GitHub - Source code and issues
- TypeScript Handbook - TypeScript best practices