Hint
If a value can be computed from existing state or props, compute it during render — don't store it in separate state. Redundant state causes sync bugs (useEffect setting derived state causes an extra render).
// Anti-pattern: derived state stored redundantly
let items = ['a', 'b', 'c'];
let count = 0; // duplicated derived state
// Every time items changes, you'd need to sync count with useEffect
// But count is always derivable — just compute it
// Correct: derive during render
function render(items) {
const count = items.length; // derived, not stored
const isEmpty = count === 0; // also derived
return { count, isEmpty };
}
const view = render(items);
console.log(view.count);
console.log(view.isEmpty);
items = [];
const view2 = render(items);
console.log(view2.count);
console.log(view2.isEmpty);3 false 0 true
Explanation: count and isEmpty are derived from items and recomputed on each render call. No synchronization needed, no risk of being out of sync.
Key Insight: If a value can be computed from existing state or props, compute it during render — don't store it in separate state. Redundant state causes sync bugs (useEffect setting derived state causes an extra render).