Sunday, November 16, 2025
Performance Optimization with QuantaJS: A Complete Guide
Posted by

Performance Optimization with QuantaJS: A Complete Guide
Performance is crucial for creating smooth, responsive user experiences. QuantaJS is designed with performance in mind, but understanding how to use it effectively can make a significant difference in your application's speed and responsiveness. In this guide, we'll explore practical strategies to optimize your QuantaJS applications.
Understanding QuantaJS Performance Characteristics
QuantaJS uses a reactive system that tracks dependencies and only updates what's necessary. However, like any state management solution, improper usage can lead to performance issues. Let's explore how to avoid common pitfalls and maximize performance.
1. Use Selectors for Fine-Grained Updates
One of the most important performance optimizations is using selectors to subscribe only to the data you need.
❌ Bad: Subscribing to Entire Store
function UserProfile() {
const store = useStore('user');
// Component re-renders on ANY store change
return <div>{store.name}</div>;
}
✅ Good: Using Selectors
function UserProfile() {
// Only re-renders when name changes
const name = useStore('user', store => store.name);
return <div>{name}</div>;
}
Real-World Example: Todo List
// ❌ Bad: Re-renders entire list when any todo changes
function TodoList() {
const store = useStore('todos');
return (
<ul>
{store.todos.map(todo => (
<TodoItem key={todo.id} todo={todo} />
))}
</ul>
);
}
// ✅ Good: Only re-renders when todos array changes
function TodoList() {
const todos = useStore('todos', store => store.todos);
return (
<ul>
{todos.map(todo => (
<TodoItem key={todo.id} todo={todo} />
))}
</ul>
);
}
// ✅ Better: Individual items only re-render when their data changes
function TodoItem({ todoId }) {
const todo = useStore('todos', store =>
store.todos.find(t => t.id === todoId)
);
return <li>{todo?.text}</li>;
}
2. Optimize Computed Values (Getters)
Computed values are cached and only recalculate when dependencies change. Use them effectively:
✅ Good: Computed Values for Derived State
const todoStore = createStore('todos', {
state: () => ({
todos: [],
filter: 'all'
}),
getters: {
// Only recalculates when todos or filter changes
filteredTodos: (state) => {
switch (state.filter) {
case 'active':
return state.todos.filter(t => !t.done);
case 'completed':
return state.todos.filter(t => t.done);
default:
return state.todos;
}
},
// Cached until dependencies change
completedCount: (state) =>
state.todos.filter(t => t.done).length,
activeCount: (state) =>
state.todos.filter(t => !t.done).length
}
});
❌ Avoid: Expensive Operations in Components
// ❌ Bad: Recalculates on every render
function TodoStats() {
const todos = useStore('todos', store => store.todos);
const completed = todos.filter(t => t.done).length; // Expensive!
return <div>Completed: {completed}</div>;
}
// ✅ Good: Use computed getter
function TodoStats() {
const completedCount = useStore('todos', store => store.completedCount);
return <div>Completed: {completedCount}</div>;
}
3. Optimize Watch Usage
The watch function is powerful but can impact performance if not used carefully.
✅ Good: Specific Watchers
// Only watches specific value
watch(() => userStore.userId, (userId) => {
if (userId) {
fetchUserData(userId);
}
});
❌ Avoid: Watching Large Objects
// ❌ Bad: Watches entire large object
watch(() => appStore, (store) => {
// This triggers on ANY change to the store
console.log('Store changed');
});
// ✅ Good: Watch specific values
watch(() => appStore.currentView, (view) => {
console.log('View changed:', view);
});
Deep Watching Considerations
// ⚠️ Use deep watching sparingly - it uses polling
watch(() => settingsStore.preferences, (prefs) => {
// Only use deep: true when necessary
}, { deep: true });
// ✅ Better: Watch specific nested properties
watch(() => settingsStore.preferences.theme, (theme) => {
applyTheme(theme);
});
4. Store Organization Strategies
How you organize your stores can significantly impact performance.
✅ Good: Domain-Based Stores
// Separate stores by domain
const userStore = createStore('user', { /* ... */ });
const cartStore = createStore('cart', { /* ... */ });
const settingsStore = createStore('settings', { /* ... */ });
// Components only subscribe to what they need
function CartSummary() {
const total = useStore('cart', store => store.total);
return <div>Total: ${total}</div>;
}
❌ Avoid: Monolithic Stores
// ❌ Bad: One giant store
const appStore = createStore('app', {
state: () => ({
user: { /* ... */ },
cart: { /* ... */ },
settings: { /* ... */ },
todos: { /* ... */ },
// ... everything in one store
})
});
// Any change triggers re-renders in all components
5. Minimize State Updates
Reduce the number of state updates by batching changes when possible.
✅ Good: Batch Updates
const todoStore = createStore('todos', {
state: () => ({ todos: [] }),
actions: {
// Single update instead of multiple
addMultipleTodos(newTodos) {
this.todos = [...this.todos, ...newTodos];
},
// Batch filter updates
updateFilters(filters) {
Object.assign(this.filters, filters);
}
}
});
❌ Avoid: Multiple Sequential Updates
// ❌ Bad: Multiple updates trigger multiple re-renders
function addTodos() {
todoStore.addTodo(todo1); // Re-render
todoStore.addTodo(todo2); // Re-render
todoStore.addTodo(todo3); // Re-render
}
// ✅ Good: Single batch update
function addTodos() {
todoStore.addMultipleTodos([todo1, todo2, todo3]); // One re-render
}
6. Use Component-Scoped Stores When Appropriate
For local state that doesn't need to be shared, use component-scoped stores.
✅ Good: Component-Scoped State
function TodoForm() {
// Local state - doesn't affect other components
const formStore = useCreateStore('todo-form', () => ({
text: '',
priority: 'medium'
}));
return (
<form>
<input
value={formStore.text}
onChange={(e) => formStore.text = e.target.value}
/>
</form>
);
}
When to Use Component-Scoped vs Global Stores
- Component-Scoped: Form state, UI state (modals, dropdowns), temporary data
- Global Stores: User data, cart, settings, shared application state
7. Optimize Persistence
Persistence can impact performance if not configured properly.
✅ Good: Selective Persistence
const appStore = createStore('app', {
state: () => ({
user: null,
settings: {},
temporaryData: [],
cache: new Map()
}),
persist: {
adapter: new LocalStorageAdapter('app-store'),
// Only persist what's necessary
include: ['user', 'settings'],
exclude: ['temporaryData', 'cache'],
// Debounce saves
debounceMs: 500
}
});
⚠️ Avoid: Persisting Everything
// ❌ Bad: Persisting large, frequently-changing data
persist: {
adapter: new LocalStorageAdapter('store'),
// Persists everything, including large arrays
}
8. Performance Monitoring
Use QuantaJS logger to monitor performance in development.
import { logger, LogLevel } from '@quantajs/core';
// Configure logger for development
if (process.env.NODE_ENV === 'development') {
logger.configure({
level: LogLevel.DEBUG,
prefix: 'Performance'
});
}
// Log store operations
const todoStore = createStore('todos', {
state: () => ({ todos: [] }),
actions: {
addTodo(text) {
const start = performance.now();
this.todos.push({ id: Date.now(), text });
const end = performance.now();
logger.debug(`addTodo took ${end - start}ms`);
}
}
});
9. React-Specific Optimizations
Use useQuantaStore for Direct Store References
// ✅ Good: Direct store reference with selector
function CartIcon() {
const itemCount = useQuantaStore(cartStore, store => store.itemCount);
return <span>{itemCount}</span>;
}
// This avoids context lookups and is more performant
Memoize Expensive Selectors
import { useMemo } from 'react';
function ExpensiveComponent() {
const todos = useStore('todos', store => store.todos);
// Memoize expensive computations
const expensiveValue = useMemo(() => {
return todos
.filter(/* complex filter */)
.map(/* complex map */)
.reduce(/* complex reduce */);
}, [todos]);
return <div>{expensiveValue}</div>;
}
10. Best Practices Summary
✅ Do's
- Use selectors to subscribe only to needed data
- Leverage computed values (getters) for derived state
- Organize stores by domain
- Use component-scoped stores for local state
- Batch related state updates
- Configure persistence selectively
- Use
useQuantaStorefor direct store access when appropriate
❌ Don'ts
- Don't subscribe to entire stores when you only need specific values
- Don't perform expensive calculations in components
- Don't watch large objects unnecessarily
- Don't create monolithic stores
- Don't persist everything
- Don't make multiple sequential updates when you can batch them
Real-World Example: Optimized E-Commerce Store
// Optimized store structure
const productStore = createStore('products', {
state: () => ({
products: [],
filters: { category: 'all', priceRange: [0, 1000] },
sortBy: 'name'
}),
getters: {
// Computed: Only recalculates when dependencies change
filteredProducts: (state) => {
return state.products
.filter(p => {
const categoryMatch = state.filters.category === 'all' ||
p.category === state.filters.category;
const priceMatch = p.price >= state.filters.priceRange[0] &&
p.price <= state.filters.priceRange[1];
return categoryMatch && priceMatch;
})
.sort((a, b) => {
// Sort logic based on sortBy
});
},
productCount: (state) => state.products.length
},
actions: {
// Batch filter updates
updateFilters(newFilters) {
Object.assign(this.filters, newFilters);
}
}
});
// Optimized components
function ProductList() {
// Only subscribes to filtered products
const products = useStore('products', store => store.filteredProducts);
return (
<div>
{products.map(product => (
<ProductCard key={product.id} productId={product.id} />
))}
</div>
);
}
function ProductCard({ productId }) {
// Individual cards only re-render when their product changes
const product = useStore('products', store =>
store.products.find(p => p.id === productId)
);
return <div>{product?.name}</div>;
}
function ProductFilters() {
// Only subscribes to filter state
const filters = useStore('products', store => store.filters);
const updateFilters = useStore('products', store => store.updateFilters);
return (
<div>
{/* Filter UI */}
</div>
);
}
Performance Checklist
Before deploying your QuantaJS application, check:
- Are you using selectors instead of subscribing to entire stores?
- Are expensive calculations in computed getters?
- Are stores organized by domain?
- Is persistence configured selectively?
- Are state updates batched when possible?
- Are you using component-scoped stores for local state?
- Are watch functions watching specific values?
- Is deep watching used only when necessary?
Conclusion
Performance optimization in QuantaJS is about understanding how reactivity works and using the right patterns for your use case. By following these guidelines, you can build fast, responsive applications that scale well.
Remember:
- Measure first: Use browser DevTools to identify bottlenecks
- Optimize incrementally: Don't over-optimize prematurely
- Test performance: Monitor your app's performance in production
Happy optimizing! 🚀