Derived State
Problem
Storing computed values as separate state creates sync bugs where derived data becomes stale. Keeping cart total in state means updating it every time items change, and forgetting one update shows wrong totals. Multiple state declarations track values that should be calculated from other state, leading to impossible states where filtered list length doesn’t match the actual filtered items.
Solution
Calculate values from props or state during render rather than storing them separately. This eliminates synchronization bugs where derived values drift out of sync with their sources.
Example
This example demonstrates deriving the cart total from item prices instead of storing it as separate state, ensuring it stays synchronized automatically.
// Web Component that computes values instead of storing them
class ShoppingCart extends HTMLElement {
set items(value) {
// Only store source data - derived values will be calculated
this._items = value;
this.render();
}
get total() {
// Derive total from items - always stays in sync with cart contents
// No separate state means no risk of stale totals
return this._items.reduce((sum, item) => sum + item.price, 0);
}
render() {
// Access derived value - it's always up to date
this.innerHTML = `<div>Total: $${this.total}</div>`;
}
}
Benefits
- Eliminates synchronization bugs where derived state becomes stale.
- Reduces state complexity by avoiding redundant data storage.
- Makes state updates simpler since you only change source data.
- Ensures derived values always reflect current state automatically.
- Easier to reason about with single source of truth.
Tradeoffs
- Can cause performance issues if derivations are expensive and run every render.
- May require memoization to avoid unnecessary recalculations.
- Can make debugging harder when values are computed rather than stored.
- Some derived values may need to be memoized adding complexity.
- Not suitable for values that need to persist independent of source state.